Skip to content

Commit 78a16b0

Browse files
committed
patch 8.0.1708: mkdir with 'p' flag fails on existing directory
Problem: Mkdir with 'p' flag fails on existing directory, which is different from the mkdir shell command. Solution: Don't fail if the directory already exists. (James McCoy, closes #2775)
1 parent 98da6ec commit 78a16b0

File tree

4 files changed

+43
-12
lines changed

4 files changed

+43
-12
lines changed

runtime/doc/eval.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6138,6 +6138,8 @@ mkdir({name} [, {path} [, {prot}]])
61386138
Example: >
61396139
:call mkdir($HOME . "/tmp/foo/bar", "p", 0700)
61406140
< This function is not available in the |sandbox|.
6141+
There is no error if the directory already exists and the "p"
6142+
flag is passed (since patch 8.0.1708).
61416143
Not available on all systems. To check use: >
61426144
:if exists("*mkdir")
61436145
<

src/evalfunc.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8057,22 +8057,32 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
80578057

80588058
dir = get_tv_string_buf(&argvars[0], buf);
80598059
if (*dir == NUL)
8060-
rettv->vval.v_number = FAIL;
8061-
else
8062-
{
8063-
if (*gettail(dir) == NUL)
8064-
/* remove trailing slashes */
8065-
*gettail_sep(dir) = NUL;
8060+
return;
80668061

8067-
if (argvars[1].v_type != VAR_UNKNOWN)
8062+
if (*gettail(dir) == NUL)
8063+
/* remove trailing slashes */
8064+
*gettail_sep(dir) = NUL;
8065+
8066+
if (argvars[1].v_type != VAR_UNKNOWN)
8067+
{
8068+
if (argvars[2].v_type != VAR_UNKNOWN)
80688069
{
8069-
if (argvars[2].v_type != VAR_UNKNOWN)
8070-
prot = (int)get_tv_number_chk(&argvars[2], NULL);
8071-
if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8072-
mkdir_recurse(dir, prot);
8070+
prot = (int)get_tv_number_chk(&argvars[2], NULL);
8071+
if (prot == -1)
8072+
return;
8073+
}
8074+
if (STRCMP(get_tv_string(&argvars[1]), "p") == 0)
8075+
{
8076+
if (mch_isdir(dir))
8077+
{
8078+
/* With the "p" flag it's OK if the dir already exists. */
8079+
rettv->vval.v_number = OK;
8080+
return;
8081+
}
8082+
mkdir_recurse(dir, prot);
80738083
}
8074-
rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
80758084
}
8085+
rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
80768086
}
80778087
#endif
80788088

src/testdir/test_eval_stuff.vim

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,20 @@ func Test_nocatch_restore_silent_emsg()
2525
let c5 = nr2char(screenchar(&lines, 5))
2626
call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
2727
endfunc
28+
29+
func Test_mkdir_p()
30+
call mkdir('Xmkdir/nested', 'p')
31+
call assert_true(isdirectory('Xmkdir/nested'))
32+
try
33+
" Trying to make existing directories doesn't error
34+
call mkdir('Xmkdir', 'p')
35+
call mkdir('Xmkdir/nested', 'p')
36+
catch /E739:/
37+
call assert_report('mkdir(..., "p") failed for an existing directory')
38+
endtry
39+
" 'p' doesn't suppress real errors
40+
call writefile([], 'Xfile')
41+
call assert_fails('call mkdir("Xfile", "p")', 'E739')
42+
call delete('Xfile')
43+
call delete('Xmkdir', 'rf')
44+
endfunc

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,8 @@ static char *(features[]) =
762762

763763
static int included_patches[] =
764764
{ /* Add new patch number below this line */
765+
/**/
766+
1708,
765767
/**/
766768
1707,
767769
/**/

0 commit comments

Comments
 (0)