LCOV - differential code coverage report
Current view: top level - src/port - pgmkdirp.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 75.0 % 32 24 8 24
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 1 1 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       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 CBC         528 : pg_mkdir_p(char *path, int omode)
      58                 : {
      59                 :     struct stat sb;
      60                 :     mode_t      numask,
      61                 :                 oumask;
      62                 :     int         last,
      63                 :                 retval;
      64                 :     char       *p;
      65                 : 
      66             528 :     retval = 0;
      67             528 :     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             528 :     oumask = umask(0);
     104             528 :     numask = oumask & ~(S_IWUSR | S_IXUSR);
     105             528 :     (void) umask(numask);
     106                 : 
     107             528 :     if (p[0] == '/')            /* Skip leading '/'. */
     108             528 :         ++p;
     109           49011 :     for (last = 0; !last; ++p)
     110                 :     {
     111           48483 :         if (p[0] == '\0')
     112             528 :             last = 1;
     113           47955 :         else if (p[0] != '/')
     114           43478 :             continue;
     115            5005 :         *p = '\0';
     116            5005 :         if (!last && p[1] == '\0')
     117 UBC           0 :             last = 1;
     118                 : 
     119 CBC        5005 :         if (last)
     120             528 :             (void) umask(oumask);
     121                 : 
     122                 :         /* check for pre-existing directory */
     123            5005 :         if (stat(path, &sb) == 0)
     124                 :         {
     125            4386 :             if (!S_ISDIR(sb.st_mode))
     126                 :             {
     127 UBC           0 :                 if (last)
     128               0 :                     errno = EEXIST;
     129                 :                 else
     130               0 :                     errno = ENOTDIR;
     131               0 :                 retval = -1;
     132               0 :                 break;
     133                 :             }
     134                 :         }
     135 CBC         619 :         else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
     136                 :         {
     137 UBC           0 :             retval = -1;
     138               0 :             break;
     139                 :         }
     140 CBC        5005 :         if (!last)
     141            4477 :             *p = '/';
     142                 :     }
     143                 : 
     144                 :     /* ensure we restored umask */
     145             528 :     (void) umask(oumask);
     146                 : 
     147             528 :     return retval;
     148                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a