LCOV - code coverage report
Current view: top level - basic - mkdir.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 55 89 61.8 %
Date: 2019-08-23 13:36:53 Functions: 7 8 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 32 96 33.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <stdbool.h>
       5                 :            : #include <string.h>
       6                 :            : #include <sys/stat.h>
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "format-util.h"
      10                 :            : #include "fs-util.h"
      11                 :            : #include "macro.h"
      12                 :            : #include "mkdir.h"
      13                 :            : #include "path-util.h"
      14                 :            : #include "stat-util.h"
      15                 :            : #include "stdio-util.h"
      16                 :            : #include "user-util.h"
      17                 :            : 
      18                 :          4 : int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) {
      19                 :            :         struct stat st;
      20                 :            :         int r;
      21                 :            : 
      22         [ -  + ]:          4 :         assert(_mkdir != mkdir);
      23                 :            : 
      24         [ +  - ]:          4 :         if (_mkdir(path, mode) >= 0) {
      25                 :          4 :                 r = chmod_and_chown(path, mode, uid, gid);
      26         [ -  + ]:          4 :                 if (r < 0)
      27                 :          0 :                         return r;
      28                 :            :         }
      29                 :            : 
      30         [ -  + ]:          4 :         if (lstat(path, &st) < 0)
      31                 :          0 :                 return -errno;
      32                 :            : 
      33   [ -  +  #  # ]:          4 :         if ((flags & MKDIR_FOLLOW_SYMLINK) && S_ISLNK(st.st_mode)) {
      34         [ #  # ]:          0 :                 _cleanup_free_ char *p = NULL;
      35                 :            : 
      36                 :          0 :                 r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p);
      37         [ #  # ]:          0 :                 if (r < 0)
      38                 :          0 :                         return r;
      39         [ #  # ]:          0 :                 if (r == 0)
      40                 :          0 :                         return mkdir_safe_internal(p, mode, uid, gid,
      41                 :          0 :                                                    flags & ~MKDIR_FOLLOW_SYMLINK,
      42                 :            :                                                    _mkdir);
      43                 :            : 
      44         [ #  # ]:          0 :                 if (lstat(p, &st) < 0)
      45                 :          0 :                         return -errno;
      46                 :            :         }
      47                 :            : 
      48         [ -  + ]:          4 :         if (!S_ISDIR(st.st_mode)) {
      49   [ #  #  #  # ]:          0 :                 log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
      50                 :            :                          "Path \"%s\" already exists and is not a directory, refusing.", path);
      51                 :          0 :                 return -ENOTDIR;
      52                 :            :         }
      53         [ +  - ]:          4 :         if ((st.st_mode & 0007) > (mode & 0007) ||
      54         [ +  - ]:          4 :             (st.st_mode & 0070) > (mode & 0070) ||
      55         [ -  + ]:          4 :             (st.st_mode & 0700) > (mode & 0700)) {
      56   [ #  #  #  # ]:          0 :                 log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
      57                 :            :                          "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.",
      58                 :            :                          path, st.st_mode & 0777, mode);
      59                 :          0 :                 return -EEXIST;
      60                 :            :         }
      61   [ +  -  +  -  :          4 :         if ((uid != UID_INVALID && st.st_uid != uid) ||
                   +  - ]
      62         [ -  + ]:          4 :             (gid != GID_INVALID && st.st_gid != gid)) {
      63                 :          0 :                 char u[DECIMAL_STR_MAX(uid_t)] = "-", g[DECIMAL_STR_MAX(gid_t)] = "-";
      64                 :            : 
      65         [ #  # ]:          0 :                 if (uid != UID_INVALID)
      66         [ #  # ]:          0 :                         xsprintf(u, UID_FMT, uid);
      67         [ #  # ]:          0 :                 if (gid != UID_INVALID)
      68         [ #  # ]:          0 :                         xsprintf(g, GID_FMT, gid);
      69   [ #  #  #  # ]:          0 :                 log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG,
      70                 :            :                          "Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.",
      71                 :            :                          path, st.st_uid, st.st_gid, u, g);
      72                 :          0 :                 return -EEXIST;
      73                 :            :         }
      74                 :            : 
      75                 :          4 :         return 0;
      76                 :            : }
      77                 :            : 
      78                 :       1152 : int mkdir_errno_wrapper(const char *pathname, mode_t mode) {
      79         [ +  + ]:       1152 :         if (mkdir(pathname, mode) < 0)
      80                 :        892 :                 return -errno;
      81                 :        260 :         return 0;
      82                 :            : }
      83                 :            : 
      84                 :          0 : int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
      85         [ #  # ]:          0 :         if (mkdirat(dirfd, pathname, mode) < 0)
      86                 :          0 :                 return -errno;
      87                 :          0 :         return 0;
      88                 :            : }
      89                 :            : 
      90                 :          4 : int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
      91                 :          4 :         return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper);
      92                 :            : }
      93                 :            : 
      94                 :        856 : int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
      95                 :            :         const char *p, *e;
      96                 :            :         int r;
      97                 :            : 
      98         [ -  + ]:        856 :         assert(path);
      99         [ -  + ]:        856 :         assert(_mkdir != mkdir);
     100                 :            : 
     101   [ -  +  #  # ]:        856 :         if (prefix && !path_startswith(path, prefix))
     102                 :          0 :                 return -ENOTDIR;
     103                 :            : 
     104                 :            :         /* return immediately if directory exists */
     105                 :        856 :         e = strrchr(path, '/');
     106         [ -  + ]:        856 :         if (!e)
     107                 :          0 :                 return -EINVAL;
     108                 :            : 
     109         [ -  + ]:        856 :         if (e == path)
     110                 :          0 :                 return 0;
     111                 :            : 
     112                 :        856 :         p = strndupa(path, e - path);
     113                 :        856 :         r = is_dir(p, true);
     114         [ +  + ]:        856 :         if (r > 0)
     115                 :        648 :                 return 0;
     116         [ -  + ]:        208 :         if (r == 0)
     117                 :          0 :                 return -ENOTDIR;
     118                 :            : 
     119                 :            :         /* create every parent directory in the path, except the last component */
     120                 :        208 :         p = path + strspn(path, "/");
     121                 :        928 :         for (;;) {
     122                 :       1136 :                 char t[strlen(path) + 1];
     123                 :            : 
     124                 :       1136 :                 e = p + strcspn(p, "/");
     125                 :       1136 :                 p = e + strspn(e, "/");
     126                 :            : 
     127                 :            :                 /* Is this the last component? If so, then we're done */
     128         [ +  + ]:       1136 :                 if (*p == 0)
     129                 :        208 :                         return 0;
     130                 :            : 
     131                 :        928 :                 memcpy(t, path, e - path);
     132                 :        928 :                 t[e-path] = 0;
     133                 :            : 
     134   [ -  +  #  # ]:        928 :                 if (prefix && path_startswith(prefix, t))
     135                 :          0 :                         continue;
     136                 :            : 
     137                 :        928 :                 r = _mkdir(t, mode);
     138   [ +  +  -  + ]:        928 :                 if (r < 0 && r != -EEXIST)
     139                 :          0 :                         return r;
     140                 :            :         }
     141                 :            : }
     142                 :            : 
     143                 :        296 : int mkdir_parents(const char *path, mode_t mode) {
     144                 :        296 :         return mkdir_parents_internal(NULL, path, mode, mkdir_errno_wrapper);
     145                 :            : }
     146                 :            : 
     147                 :         28 : int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
     148                 :            :         int r;
     149                 :            : 
     150                 :            :         /* Like mkdir -p */
     151                 :            : 
     152         [ -  + ]:         28 :         assert(_mkdir != mkdir);
     153                 :            : 
     154                 :         28 :         r = mkdir_parents_internal(prefix, path, mode, _mkdir);
     155         [ -  + ]:         28 :         if (r < 0)
     156                 :          0 :                 return r;
     157                 :            : 
     158                 :         28 :         r = _mkdir(path, mode);
     159   [ -  +  #  #  :         28 :         if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
                   #  # ]
     160                 :          0 :                 return r;
     161                 :            : 
     162                 :         28 :         return 0;
     163                 :            : }
     164                 :            : 
     165                 :         24 : int mkdir_p(const char *path, mode_t mode) {
     166                 :         24 :         return mkdir_p_internal(NULL, path, mode, mkdir_errno_wrapper);
     167                 :            : }

Generated by: LCOV version 1.14