LCOV - code coverage report
Current view: top level - basic - mkdir.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 55 89 61.8 %
Date: 2019-08-22 15:41:25 Functions: 7 8 87.5 %

          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           1 : 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           1 :         assert(_mkdir != mkdir);
      23             : 
      24           1 :         if (_mkdir(path, mode) >= 0) {
      25           1 :                 r = chmod_and_chown(path, mode, uid, gid);
      26           1 :                 if (r < 0)
      27           0 :                         return r;
      28             :         }
      29             : 
      30           1 :         if (lstat(path, &st) < 0)
      31           0 :                 return -errno;
      32             : 
      33           1 :         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           1 :         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           1 :         if ((st.st_mode & 0007) > (mode & 0007) ||
      54           1 :             (st.st_mode & 0070) > (mode & 0070) ||
      55           1 :             (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           1 :         if ((uid != UID_INVALID && st.st_uid != uid) ||
      62           1 :             (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           1 :         return 0;
      76             : }
      77             : 
      78         288 : int mkdir_errno_wrapper(const char *pathname, mode_t mode) {
      79         288 :         if (mkdir(pathname, mode) < 0)
      80         223 :                 return -errno;
      81          65 :         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           1 : int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
      91           1 :         return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper);
      92             : }
      93             : 
      94         214 : 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         214 :         assert(path);
      99         214 :         assert(_mkdir != mkdir);
     100             : 
     101         214 :         if (prefix && !path_startswith(path, prefix))
     102           0 :                 return -ENOTDIR;
     103             : 
     104             :         /* return immediately if directory exists */
     105         214 :         e = strrchr(path, '/');
     106         214 :         if (!e)
     107           0 :                 return -EINVAL;
     108             : 
     109         214 :         if (e == path)
     110           0 :                 return 0;
     111             : 
     112         214 :         p = strndupa(path, e - path);
     113         214 :         r = is_dir(p, true);
     114         214 :         if (r > 0)
     115         162 :                 return 0;
     116          52 :         if (r == 0)
     117           0 :                 return -ENOTDIR;
     118             : 
     119             :         /* create every parent directory in the path, except the last component */
     120          52 :         p = path + strspn(path, "/");
     121         232 :         for (;;) {
     122         284 :                 char t[strlen(path) + 1];
     123             : 
     124         284 :                 e = p + strcspn(p, "/");
     125         284 :                 p = e + strspn(e, "/");
     126             : 
     127             :                 /* Is this the last component? If so, then we're done */
     128         284 :                 if (*p == 0)
     129          52 :                         return 0;
     130             : 
     131         232 :                 memcpy(t, path, e - path);
     132         232 :                 t[e-path] = 0;
     133             : 
     134         232 :                 if (prefix && path_startswith(prefix, t))
     135           0 :                         continue;
     136             : 
     137         232 :                 r = _mkdir(t, mode);
     138         232 :                 if (r < 0 && r != -EEXIST)
     139           0 :                         return r;
     140             :         }
     141             : }
     142             : 
     143          74 : int mkdir_parents(const char *path, mode_t mode) {
     144          74 :         return mkdir_parents_internal(NULL, path, mode, mkdir_errno_wrapper);
     145             : }
     146             : 
     147           7 : 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           7 :         assert(_mkdir != mkdir);
     153             : 
     154           7 :         r = mkdir_parents_internal(prefix, path, mode, _mkdir);
     155           7 :         if (r < 0)
     156           0 :                 return r;
     157             : 
     158           7 :         r = _mkdir(path, mode);
     159           7 :         if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
     160           0 :                 return r;
     161             : 
     162           7 :         return 0;
     163             : }
     164             : 
     165           6 : int mkdir_p(const char *path, mode_t mode) {
     166           6 :         return mkdir_p_internal(NULL, path, mode, mkdir_errno_wrapper);
     167             : }

Generated by: LCOV version 1.14