提交 bd8abd95 编写于 作者: N Ning Yu

Fix race condition in pg_mkdir_p()

pg_mkdir_p() is used by initdb and pg_basebackup to create a directory
as well as its parent directories.  The logic used to be like below:

    if (stat(path) < 0)
    {
        if (mkdir(path) < 0)
            retval = -1;
    }

It first checks for the existence of the path, if path does not
pre-exist then it creates the directory.  However if two processes try
to create path concurrently, then one possible execution order is as
below:

    A: stat(path) returns -1, so decide to create it;
    B: stat(path) returns -1, so decide to create it;
    B: mkdir(path) returns 0, successfully created path;
    A: mkdir(path) returns -1, fail to create path as it already exist;

This race condition could be fixed by swapping the order of stat() and
mkdir(), this is also what the "mkdir -p" command does.
Co-authored-by: NPaul Guo <pguo@pivotal.io>
Co-authored-by: NNing Yu <nyu@pivotal.io>
上级 434e5e3d
......@@ -119,11 +119,22 @@ pg_mkdir_p(char *path, int omode)
if (last)
(void) umask(oumask);
/* check for pre-existing directory */
if (stat(path, &sb) == 0)
if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) == 0)
{
if (!S_ISDIR(sb.st_mode))
/* path does not pre-exist and is successfully created */
}
else if (errno == EEXIST)
{
/* path exists, double check it is a dir */
if (stat(path, &sb) < 0)
{
retval = -1;
break;
}
else if (!S_ISDIR(sb.st_mode))
{
/* path is not a dir at all */
if (last)
errno = EEXIST;
else
......@@ -131,8 +142,10 @@ pg_mkdir_p(char *path, int omode)
retval = -1;
break;
}
/* now we know that path is a dir */
}
else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
else
{
retval = -1;
break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册