summaryrefslogtreecommitdiffstats
path: root/src/basic/mkdir.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-09-02 09:12:16 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-09-07 07:08:18 +0200
commit3008a6f21c1c42efe852d69798a2fdd63fe657ec (patch)
tree940cab95f8be6459582bf60a4136d4835452dcdd /src/basic/mkdir.c
parentMerge pull request #20465 from bluca/portable_validate_sysext (diff)
downloadsystemd-3008a6f21c1c42efe852d69798a2fdd63fe657ec.tar.xz
systemd-3008a6f21c1c42efe852d69798a2fdd63fe657ec.zip
mkdir: rewrite mkdir_parents() with path_find_{first,last}_component()
Diffstat (limited to 'src/basic/mkdir.c')
-rw-r--r--src/basic/mkdir.c62
1 files changed, 35 insertions, 27 deletions
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index f91f8f7a08..78f540809f 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -95,57 +95,65 @@ int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags f
}
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) {
- const char *p, *e;
+ const char *p, *e = NULL;
int r;
assert(path);
assert(_mkdir != mkdir);
- if (prefix && !path_startswith(path, prefix))
+ if (prefix) {
+ p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false);
+ if (!p)
+ return -ENOTDIR;
+ } else
+ p = path;
+
+ if (isempty(p))
+ return 0;
+
+ if (!path_is_safe(p))
return -ENOTDIR;
/* return immediately if directory exists */
- e = strrchr(path, '/');
- if (!e)
+ r = path_find_last_component(p, /* accept_dot_dot= */ false, &e, NULL);
+ if (r <= 0) /* r == 0 means path is equivalent to prefix. */
+ return r;
+ if (e == p)
return 0;
- if (e == path)
- return 0;
+ assert(e > p);
+ assert(*e == '/');
- p = strndupa(path, e - path);
- r = is_dir(p, true);
+ /* drop the last component */
+ path = strndupa(path, e - path);
+ r = is_dir(path, true);
if (r > 0)
return 0;
if (r == 0)
return -ENOTDIR;
/* create every parent directory in the path, except the last component */
- p = path + strspn(path, "/");
- for (;;) {
- char t[strlen(path) + 1];
+ for (p = path;;) {
+ char *s;
+ int n;
- e = p + strcspn(p, "/");
- p = e + strspn(e, "/");
+ n = path_find_first_component(&p, /* accept_dot_dot= */ false, (const char **) &s);
+ if (n <= 0)
+ return n;
- /* Is this the last component? If so, then we're done */
- if (*p == 0)
- return 0;
-
- memcpy(t, path, e - path);
- t[e-path] = 0;
+ assert(p);
+ assert(s >= path);
+ assert(IN_SET(s[n], '/', '\0'));
- if (prefix && path_startswith(prefix, t))
- continue;
+ s[n] = '\0';
- if (!uid_is_valid(uid) && !gid_is_valid(gid) && flags == 0) {
- r = _mkdir(t, mode);
- if (r < 0 && r != -EEXIST)
- return r;
- } else {
- r = mkdir_safe_internal(t, mode, uid, gid, flags, _mkdir);
+ if (!prefix || !path_startswith_full(prefix, path, /* accept_dot_dot= */ false)) {
+ r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdir);
if (r < 0 && r != -EEXIST)
return r;
}
+
+ s[n] = *p == '\0' ? '\0' : '/';
}
}