YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/postgres/src/port/pgmkdirp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This is adapted from FreeBSD's src/bin/mkdir/mkdir.c, which bears
3
 * the following copyright notice:
4
 *
5
 * Copyright (c) 1983, 1992, 1993
6
 *  The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 4. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include "c.h"
34
35
#include <sys/stat.h>
36
37
38
/*
39
 * pg_mkdir_p --- create a directory and, if necessary, parent directories
40
 *
41
 * This is equivalent to "mkdir -p" except we don't complain if the target
42
 * directory already exists.
43
 *
44
 * We assume the path is in canonical form, i.e., uses / as the separator.
45
 *
46
 * omode is the file permissions bits for the target directory.  Note that any
47
 * parent directories that have to be created get permissions according to the
48
 * prevailing umask, but with u+wx forced on to ensure we can create there.
49
 * (We declare omode as int, not mode_t, to minimize dependencies for port.h.)
50
 *
51
 * Returns 0 on success, -1 (with errno set) on failure.
52
 *
53
 * Note that on failure, the path arg has been modified to show the particular
54
 * directory level we had problems with.
55
 */
56
int
57
pg_mkdir_p(char *path, int omode)
58
2.00k
{
59
2.00k
  struct stat sb;
60
2.00k
  mode_t    numask,
61
2.00k
        oumask;
62
2.00k
  int     last,
63
2.00k
        retval;
64
2.00k
  char     *p;
65
66
2.00k
  retval = 0;
67
2.00k
  p = path;
68
69
#ifdef WIN32
70
  /* skip network and drive specifiers for win32 */
71
  if (strlen(p) >= 2)
72
  {
73
    if (p[0] == '/' && p[1] == '/')
74
    {
75
      /* network drive */
76
      p = strstr(p + 2, "/");
77
      if (p == NULL)
78
      {
79
        errno = EINVAL;
80
        return -1;
81
      }
82
    }
83
    else if (p[1] == ':' &&
84
         ((p[0] >= 'a' && p[0] <= 'z') ||
85
          (p[0] >= 'A' && p[0] <= 'Z')))
86
    {
87
      /* local drive */
88
      p += 2;
89
    }
90
  }
91
#endif
92
93
  /*
94
   * POSIX 1003.2: For each dir operand that does not name an existing
95
   * directory, effects equivalent to those caused by the following command
96
   * shall occur:
97
   *
98
   * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir
99
   *
100
   * We change the user's umask and then restore it, instead of doing
101
   * chmod's.  Note we assume umask() can't change errno.
102
   */
103
2.00k
  oumask = umask(0);
104
2.00k
  numask = oumask & ~(S_IWUSR | S_IXUSR);
105
2.00k
  (void) umask(numask);
106
107
2.00k
  if (p[0] == '/')     /* Skip leading '/'. */
108
2.00k
    ++p;
109
196k
  for (last = 0; !last; 
++p194k
)
110
194k
  {
111
194k
    if (p[0] == '\0')
112
2.00k
      last = 1;
113
192k
    else if (p[0] != '/')
114
185k
      continue;
115
9.11k
    *p = '\0';
116
9.11k
    if (!last && 
p[1] == '\0'7.10k
)
117
0
      last = 1;
118
119
9.11k
    if (last)
120
2.00k
      (void) umask(oumask);
121
122
    /* check for pre-existing directory */
123
9.11k
    if (stat(path, &sb) == 0)
124
7.09k
    {
125
7.09k
      if (!S_ISDIR(sb.st_mode))
126
0
      {
127
0
        if (last)
128
0
          errno = EEXIST;
129
0
        else
130
0
          errno = ENOTDIR;
131
0
        retval = -1;
132
0
        break;
133
0
      }
134
7.09k
    }
135
2.01k
    else if (mkdir(path, last ? 
omode2.00k
: S_IRWXU
| S_IRWXG | S_IRWXO6
) < 0)
136
0
    {
137
0
      retval = -1;
138
0
      break;
139
0
    }
140
9.11k
    if (!last)
141
7.10k
      *p = '/';
142
9.11k
  }
143
144
  /* ensure we restored umask */
145
2.00k
  (void) umask(oumask);
146
147
2.00k
  return retval;
148
2.00k
}