LCOV - differential code coverage report
Current view: top level - src/port - pgmkdirp.c (source / functions) Coverage Total Hit UBC CBC
Current: d36b728949bf4e37ada1cd23e0f2aaa94f609a70 vs 52e118fe2f7e3381bdaa479816a7f72eda2ae517 Lines: 86.7 % 30 26 4 26
Current Date: 2026-06-29 16:15:13 +0200 Functions: 100.0 % 1 1 1
Baseline: lcov-20260630-baseline Branches: 80.8 % 26 21 5 21
Baseline Date: 2026-06-29 13:01:57 +0200 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 83.3 % 6 5 1 5
(360..) days: 87.5 % 24 21 3 21
Function coverage date bins:
(360..) days: 100.0 % 1 1 1
Branch coverage date bins:
(7,30] days: 70.0 % 10 7 3 7
(360..) days: 87.5 % 16 14 2 14

 Age         Owner                    Branch data    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
 5681 tgl@sss.pgh.pa.us          57                 :CBC         564 : pg_mkdir_p(char *path, int omode)
                                 58                 :                : {
                                 59                 :                :     mode_t      numask,
                                 60                 :                :                 oumask;
                                 61                 :                :     int         last,
                                 62                 :                :                 retval;
                                 63                 :                :     char       *p;
                                 64                 :                : 
                                 65                 :            564 :     retval = 0;
                                 66                 :            564 :     p = path;
                                 67                 :                : 
                                 68                 :                : #ifdef WIN32
                                 69                 :                :     /* skip network and drive specifiers for win32 */
                                 70                 :                :     if (strlen(p) >= 2)
                                 71                 :                :     {
                                 72                 :                :         if (p[0] == '/' && p[1] == '/')
                                 73                 :                :         {
                                 74                 :                :             /* network drive */
                                 75                 :                :             p = strchr(p + 2, '/');
                                 76                 :                :             if (p == NULL)
                                 77                 :                :             {
                                 78                 :                :                 errno = EINVAL;
                                 79                 :                :                 return -1;
                                 80                 :                :             }
                                 81                 :                :         }
                                 82                 :                :         else if (p[1] == ':' &&
                                 83                 :                :                  ((p[0] >= 'a' && p[0] <= 'z') ||
                                 84                 :                :                   (p[0] >= 'A' && p[0] <= 'Z')))
                                 85                 :                :         {
                                 86                 :                :             /* local drive */
                                 87                 :                :             p += 2;
                                 88                 :                :         }
                                 89                 :                :     }
                                 90                 :                : #endif
                                 91                 :                : 
                                 92                 :                :     /*
                                 93                 :                :      * POSIX 1003.2: For each dir operand that does not name an existing
                                 94                 :                :      * directory, effects equivalent to those caused by the following command
                                 95                 :                :      * shall occur:
                                 96                 :                :      *
                                 97                 :                :      * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir
                                 98                 :                :      *
                                 99                 :                :      * We change the user's umask and then restore it, instead of doing
                                100                 :                :      * chmod's.  Note we assume umask() can't change errno.
                                101                 :                :      */
                                102                 :            564 :     oumask = umask(0);
                                103                 :            564 :     numask = oumask & ~(S_IWUSR | S_IXUSR);
                                104                 :            564 :     (void) umask(numask);
                                105                 :                : 
                                106         [ +  - ]:            564 :     if (p[0] == '/')            /* Skip leading '/'. */
                                107                 :            564 :         ++p;
                                108         [ +  + ]:          83221 :     for (last = 0; !last; ++p)
                                109                 :                :     {
                                110         [ +  + ]:          82657 :         if (p[0] == '\0')
                                111                 :            564 :             last = 1;
                                112         [ +  + ]:          82093 :         else if (p[0] != '/')
                                113                 :          75976 :             continue;
                                114                 :           6681 :         *p = '\0';
                                115   [ +  +  -  + ]:           6681 :         if (!last && p[1] == '\0')
 5681 tgl@sss.pgh.pa.us         116                 :UBC           0 :             last = 1;
                                117                 :                : 
 5681 tgl@sss.pgh.pa.us         118         [ +  + ]:CBC        6681 :         if (last)
                                119                 :            564 :             (void) umask(oumask);
                                120                 :                : 
   11                           121   [ +  +  +  + ]:           6681 :         if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
                                122                 :                :         {
                                123                 :                :             /*
                                124                 :                :              * If we got EEXIST because there's already a directory there,
                                125                 :                :              * don't complain.
                                126                 :                :              */
                                127                 :                : #ifndef WIN32
                                128                 :           5970 :             int         save_errno = errno;
                                129                 :                :             struct stat sb;
                                130                 :                : 
                                131   [ +  -  +  - ]:          11940 :             if (save_errno != EEXIST ||
                                132                 :           5970 :                 stat(path, &sb) != 0 ||
                                133         [ -  + ]:           5970 :                 !S_ISDIR(sb.st_mode))
                                134                 :                :             {
                                135                 :                :                 /* Don't let stat replace mkdir's errno */
   11 tgl@sss.pgh.pa.us         136                 :UBC           0 :                 errno = save_errno;
 5681                           137                 :              0 :                 retval = -1;
                                138                 :              0 :                 break;
                                139                 :                :             }
                                140                 :                : #else                           /* WIN32 */
                                141                 :                :             /*
                                142                 :                :              * On Windows, stat() opens a handle and can transiently fail on a
                                143                 :                :              * directory another process is concurrently creating.  Probe with
                                144                 :                :              * a path-based attribute query instead: it requests only
                                145                 :                :              * FILE_READ_ATTRIBUTES and is exempt from share-mode denial, so
                                146                 :                :              * it reliably sees a concurrently-created directory.  We assume
                                147                 :                :              * GetFileAttributes() won't change errno.
                                148                 :                :              */
                                149                 :                :             DWORD       attr = GetFileAttributes(path);
                                150                 :                : 
                                151                 :                :             if (errno != EEXIST ||
                                152                 :                :                 attr == INVALID_FILE_ATTRIBUTES ||
                                153                 :                :                 !(attr & FILE_ATTRIBUTE_DIRECTORY))
                                154                 :                :             {
                                155                 :                :                 retval = -1;
                                156                 :                :                 break;
                                157                 :                :             }
                                158                 :                : #endif                          /* WIN32 */
                                159                 :                :         }
                                160                 :                : 
 5681 tgl@sss.pgh.pa.us         161         [ +  + ]:CBC        6681 :         if (!last)
                                162                 :           6117 :             *p = '/';
                                163                 :                :     }
                                164                 :                : 
                                165                 :                :     /* ensure we restored umask */
                                166                 :            564 :     (void) umask(oumask);
                                167                 :                : 
                                168                 :            564 :     return retval;
                                169                 :                : }
        

Generated by: LCOV version 2.0-1