mirror of
https://github.com/systemd/systemd
synced 2026-03-27 09:14:51 +01:00
Compare commits
No commits in common. "dd4c15296cce001287d03a6647a751f253de2a51" and "7d50cd65bbaed9189f9d647591b980b3a2f3cce8" have entirely different histories.
dd4c15296c
...
7d50cd65bb
@ -45,39 +45,50 @@ int unlink_noerrno(const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rmdir_parents(const char *path, const char *stop) {
|
int rmdir_parents(const char *path, const char *stop) {
|
||||||
char *p;
|
size_t l;
|
||||||
int r;
|
int r = 0;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(stop);
|
assert(stop);
|
||||||
|
|
||||||
if (!path_is_safe(path))
|
l = strlen(path);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!path_is_safe(stop))
|
/* Skip trailing slashes */
|
||||||
return -EINVAL;
|
while (l > 0 && path[l-1] == '/')
|
||||||
|
l--;
|
||||||
|
|
||||||
p = strdupa(path);
|
while (l > 0) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
for (;;) {
|
/* Skip last component */
|
||||||
char *slash = NULL;
|
while (l > 0 && path[l-1] != '/')
|
||||||
|
l--;
|
||||||
|
|
||||||
/* skip the last component. */
|
/* Skip trailing slashes */
|
||||||
r = path_find_last_component(p, /* accept_dot_dot= */ false, (const char **) &slash, NULL);
|
while (l > 0 && path[l-1] == '/')
|
||||||
if (r <= 0)
|
l--;
|
||||||
return r;
|
|
||||||
if (slash == p)
|
if (l <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
t = strndup(path, l);
|
||||||
|
if (!t)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (path_startswith(stop, t)) {
|
||||||
|
free(t);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
assert(*slash == '/');
|
r = rmdir(t);
|
||||||
*slash = '\0';
|
free(t);
|
||||||
|
|
||||||
if (path_startswith_full(stop, p, /* accept_dot_dot= */ false))
|
if (r < 0)
|
||||||
return 0;
|
if (errno != ENOENT)
|
||||||
|
|
||||||
if (rmdir(p) < 0 && errno != ENOENT)
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
|
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
|
||||||
|
|||||||
@ -95,65 +95,57 @@ 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) {
|
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 = NULL;
|
const char *p, *e;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(_mkdir != mkdir);
|
assert(_mkdir != mkdir);
|
||||||
|
|
||||||
if (prefix) {
|
if (prefix && !path_startswith(path, 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 -ENOTDIR;
|
||||||
|
|
||||||
/* return immediately if directory exists */
|
/* return immediately if directory exists */
|
||||||
r = path_find_last_component(p, /* accept_dot_dot= */ false, &e, NULL);
|
e = strrchr(path, '/');
|
||||||
if (r <= 0) /* r == 0 means path is equivalent to prefix. */
|
if (!e)
|
||||||
return r;
|
|
||||||
if (e == p)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
assert(e > p);
|
if (e == path)
|
||||||
assert(*e == '/');
|
return 0;
|
||||||
|
|
||||||
/* drop the last component */
|
p = strndupa(path, e - path);
|
||||||
path = strndupa(path, e - path);
|
r = is_dir(p, true);
|
||||||
r = is_dir(path, true);
|
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
|
|
||||||
/* create every parent directory in the path, except the last component */
|
/* create every parent directory in the path, except the last component */
|
||||||
for (p = path;;) {
|
p = path + strspn(path, "/");
|
||||||
char *s;
|
for (;;) {
|
||||||
int n;
|
char t[strlen(path) + 1];
|
||||||
|
|
||||||
n = path_find_first_component(&p, /* accept_dot_dot= */ false, (const char **) &s);
|
e = p + strcspn(p, "/");
|
||||||
if (n <= 0)
|
p = e + strspn(e, "/");
|
||||||
return n;
|
|
||||||
|
|
||||||
assert(p);
|
/* Is this the last component? If so, then we're done */
|
||||||
assert(s >= path);
|
if (*p == 0)
|
||||||
assert(IN_SET(s[n], '/', '\0'));
|
return 0;
|
||||||
|
|
||||||
s[n] = '\0';
|
memcpy(t, path, e - path);
|
||||||
|
t[e-path] = 0;
|
||||||
|
|
||||||
if (!prefix || !path_startswith_full(prefix, path, /* accept_dot_dot= */ false)) {
|
if (prefix && path_startswith(prefix, t))
|
||||||
r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdir);
|
continue;
|
||||||
|
|
||||||
|
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 (r < 0 && r != -EEXIST)
|
if (r < 0 && r != -EEXIST)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
s[n] = *p == '\0' ? '\0' : '/';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -865,60 +865,6 @@ static void test_conservative_rename(void) {
|
|||||||
assert_se(access(q, F_OK) < 0 && errno == ENOENT);
|
assert_se(access(q, F_OK) < 0 && errno == ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_rmdir_parents_one(
|
|
||||||
const char *prefix,
|
|
||||||
const char *path,
|
|
||||||
const char *stop,
|
|
||||||
int expected,
|
|
||||||
const char *test_exist,
|
|
||||||
const char *test_nonexist_subdir) {
|
|
||||||
|
|
||||||
const char *p, *s;
|
|
||||||
|
|
||||||
log_debug("/* %s(%s, %s) */", __func__, path, stop);
|
|
||||||
|
|
||||||
p = strjoina(prefix, path);
|
|
||||||
s = strjoina(prefix, stop);
|
|
||||||
|
|
||||||
if (expected >= 0)
|
|
||||||
assert_se(mkdir_parents(p, 0700) >= 0);
|
|
||||||
|
|
||||||
assert_se(rmdir_parents(p, s) == expected);
|
|
||||||
|
|
||||||
if (expected >= 0) {
|
|
||||||
const char *e, *f;
|
|
||||||
|
|
||||||
e = strjoina(prefix, test_exist);
|
|
||||||
f = strjoina(e, test_nonexist_subdir);
|
|
||||||
|
|
||||||
assert_se(access(e, F_OK) >= 0);
|
|
||||||
assert_se(access(f, F_OK) < 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_rmdir_parents(void) {
|
|
||||||
char *temp;
|
|
||||||
|
|
||||||
log_info("/* %s */", __func__);
|
|
||||||
|
|
||||||
temp = strjoina(arg_test_dir ?: "/tmp", "/test-rmdir.XXXXXX");
|
|
||||||
assert_se(mkdtemp(temp));
|
|
||||||
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/../hoge/foo", "/hoge/foo", -EINVAL, NULL, NULL);
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc", "/hoge/../aaa", -EINVAL, NULL, NULL);
|
|
||||||
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/aaa/bbb/ccc/ddd", 0, "/aaa/bbb/ccc/ddd", "/eee");
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/aaa/bbb/ccc", 0, "/aaa/bbb/ccc", "/ddd");
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/aaa/bbb", 0, "/aaa/bbb", "/ccc");
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/aaa", 0, "/aaa", "/bbb");
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/", 0, "/", "/aaa");
|
|
||||||
|
|
||||||
test_rmdir_parents_one(temp, "/aaa/bbb/ccc/ddd/eee", "/aaa/hoge/foo", 0, "/aaa", "/bbb");
|
|
||||||
test_rmdir_parents_one(temp, "/aaa////bbb/.//ccc//ddd/eee///./.", "///././aaa/.", 0, "/aaa", "/bbb");
|
|
||||||
|
|
||||||
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
test_setup_logging(LOG_INFO);
|
test_setup_logging(LOG_INFO);
|
||||||
|
|
||||||
@ -937,7 +883,6 @@ int main(int argc, char *argv[]) {
|
|||||||
test_rename_noreplace();
|
test_rename_noreplace();
|
||||||
test_chmod_and_chown();
|
test_chmod_and_chown();
|
||||||
test_conservative_rename();
|
test_conservative_rename();
|
||||||
test_rmdir_parents();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,7 +126,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
if (unlink(devname) < 0)
|
if (unlink(devname) < 0)
|
||||||
return log_error_errno(errno, "unlink('%s') failed: %m", devname);
|
return log_error_errno(errno, "unlink('%s') failed: %m", devname);
|
||||||
(void) rmdir_parents(devname, "/dev");
|
(void) rmdir_parents(devname, "/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user