1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-26 14:04:03 +03:00

Merge pull request #23261 from poettering/dir-is-empty

dir_is_empty() fixes
This commit is contained in:
Lennart Poettering 2022-05-04 16:36:34 +02:00 committed by GitHub
commit 8dd11be77f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 56 additions and 48 deletions

View File

@ -71,13 +71,10 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
int dir_is_empty_at(int dir_fd, const char *path) {
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
_cleanup_close_ int fd = -1;
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */
DEFINE_DIRENT_BUFFER(buffer, 3);
struct dirent *de;
ssize_t n;
struct dirent *buf;
size_t m;
if (path) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@ -99,15 +96,30 @@ int dir_is_empty_at(int dir_fd, const char *path) {
return fd;
}
n = getdents64(fd, &buffer, sizeof(buffer));
if (n < 0)
return -errno;
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
* 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
* entries that we end up ignoring. */
m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX;
buf = alloca(m);
msan_unpoison(&buffer, n);
for (;;) {
struct dirent *de;
ssize_t n;
FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
if (!hidden_or_backup_file(de->d_name))
return 0;
n = getdents64(fd, buf, m);
if (n < 0)
return -errno;
if (n == 0)
break;
assert((size_t) n <= m);
msan_unpoison(buf, n);
FOREACH_DIRENT_IN_BUFFER(de, buf, n)
if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
return 0;
}
return 1;
}

View File

@ -17,17 +17,9 @@ int is_dir(const char *path, bool follow);
int is_dir_fd(int fd);
int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path);
static inline int dir_is_empty(const char *path) {
return dir_is_empty_at(AT_FDCWD, path);
}
static inline int dir_is_populated(const char *path) {
int r;
r = dir_is_empty(path);
if (r < 0)
return r;
return !r;
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
static inline int dir_is_empty(const char *path, bool ignore_hidden_or_backup) {
return dir_is_empty_at(AT_FDCWD, path, ignore_hidden_or_backup);
}
bool null_or_empty(struct stat *st) _pure_;

View File

@ -1639,7 +1639,7 @@ static int are_we_installed(const char *esp_path) {
return log_oom();
log_debug("Checking whether %s contains any files…", p);
r = dir_is_empty(p);
r = dir_is_empty(p, /* ignore_hidden_or_backup= */ false);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to check whether %s contains any files: %m", p);

View File

@ -1290,7 +1290,7 @@ static void test_usr(void) {
/* Check that /usr is either on the same file system as / or mounted already. */
if (dir_is_empty("/usr") <= 0)
if (dir_is_empty("/usr", /* ignore_hidden_or_backup= */ false) <= 0)
return;
log_warning("/usr appears to be on its own filesystem and is not already mounted. This is not a supported setup. "

View File

@ -976,7 +976,7 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager *
m->taint_usr =
!in_initrd() &&
dir_is_empty("/usr") > 0;
dir_is_empty("/usr", /* ignore_hidden_or_backup= */ false) > 0;
/* Note that we do not set up the notify fd here. We do that after deserialization,
* since they might have gotten serialized across the reexec. */

View File

@ -213,7 +213,7 @@ static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_no
case PATH_DIRECTORY_NOT_EMPTY: {
int k;
k = dir_is_empty(s->path);
k = dir_is_empty(s->path, /* ignore_hidden_or_backup= */ true);
good = !(IN_SET(k, -ENOENT, -ENOTDIR) || k > 0);
break;
}

View File

@ -4776,7 +4776,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
if (!unit_log_level_test(u, LOG_NOTICE))
return;
r = dir_is_empty(where);
r = dir_is_empty(where, /* ignore_hidden_or_backup= */ false);
if (r > 0 || r == -ENOTDIR)
return;
if (r < 0) {

View File

@ -305,7 +305,7 @@ static int path_is_busy(const char *where) {
return log_warning_errno(r, "Cannot check if \"%s\" is a mount point: %m", where);
/* not a mountpoint but it contains files */
r = dir_is_empty(where);
r = dir_is_empty(where, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return log_warning_errno(r, "Cannot check if \"%s\" is empty: %m", where);
if (r > 0)

View File

@ -207,7 +207,7 @@ int home_create_cifs(UserRecord *h, HomeSetup *setup, UserRecord **ret_home) {
if (r < 0)
return r;
r = dir_is_empty_at(setup->root_fd, NULL);
r = dir_is_empty_at(setup->root_fd, NULL, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return log_error_errno(r, "Failed to detect if CIFS directory is empty: %m");
if (r == 0)

View File

@ -445,7 +445,7 @@ int user_record_test_home_directory(UserRecord *h) {
}
/* Otherwise it's not OK */
r = dir_is_empty(hd);
r = dir_is_empty(hd, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return r;
if (r == 0)

View File

@ -449,7 +449,7 @@ int remove_bridge(const char *bridge_name) {
path = strjoina("/sys/class/net/", bridge_name, "/brif");
r = dir_is_empty(path);
r = dir_is_empty(path, /* ignore_hidden_or_backup= */ false);
if (r == -ENOENT) /* Already gone? */
return 0;
if (r < 0)

View File

@ -2680,7 +2680,7 @@ static int setup_journal(const char *directory) {
} else if (access(p, F_OK) < 0)
return 0;
if (dir_is_empty(q) == 0)
if (dir_is_empty(q, /* ignore_hidden_or_backup= */ false) == 0)
log_warning("%s is not empty, proceeding anyway.", q);
r = userns_mkdir(directory, p, 0755, 0, 0);

View File

@ -922,7 +922,7 @@ static int condition_test_directory_not_empty(Condition *c, char **env) {
assert(c->parameter);
assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
r = dir_is_empty(c->parameter);
r = dir_is_empty(c->parameter, /* ignore_hidden_or_backup= */ true);
return r <= 0 && !IN_SET(r, -ENOENT, -ENOTDIR);
}

View File

@ -905,7 +905,7 @@ static int fd_copy_directory(
exists = false;
if (copy_flags & COPY_MERGE_EMPTY) {
r = dir_is_empty_at(dt, to);
r = dir_is_empty_at(dt, to, /* ignore_hidden_or_backup= */ false);
if (r < 0 && r != -ENOENT)
return r;
else if (r == 1)

View File

@ -1552,7 +1552,7 @@ int dissected_image_mount(
if (r < 0) {
if (r != -ENOENT)
return r;
} else if (dir_is_empty(p) > 0) {
} else if (dir_is_empty(p, /* ignore_hidden_or_backup= */ false) > 0) {
/* It exists and is an empty directory. Let's mount the ESP there. */
r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, uid_range, flags);
if (r < 0)

View File

@ -1466,7 +1466,7 @@ Tpm2Support tpm2_support(void) {
* got the host sysfs mounted. Since devices are generally not virtualized for containers,
* let's assume containers never have a TPM, at least for now. */
r = dir_is_empty("/sys/class/tpmrm");
r = dir_is_empty("/sys/class/tpmrm", /* ignore_hidden_or_backup= */ false);
if (r < 0) {
if (r != -ENOENT)
log_debug_errno(r, "Unable to test whether /sys/class/tpmrm/ exists and is populated, assuming it is not: %m");

View File

@ -296,7 +296,7 @@ static int merge_hierarchy(
else if (r < 0)
return log_error_errno(r, "Failed to resolve host hierarchy '%s': %m", hierarchy);
else {
r = dir_is_empty(resolved_hierarchy);
r = dir_is_empty(resolved_hierarchy, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return log_error_errno(r, "Failed to check if host hierarchy '%s' is empty: %m", resolved_hierarchy);
if (r > 0) {
@ -337,7 +337,7 @@ static int merge_hierarchy(
if (r < 0)
return log_error_errno(r, "Failed to resolve hierarchy '%s' in extension '%s': %m", hierarchy, *p);
r = dir_is_empty(resolved);
r = dir_is_empty(resolved, /* ignore_hidden_or_backup= */ false);
if (r < 0)
return log_error_errno(r, "Failed to check if hierarchy '%s' in extension '%s' is empty: %m", resolved, *p);
if (r > 0) {

View File

@ -153,17 +153,17 @@ TEST(dir_is_empty) {
_cleanup_(rm_rf_physical_and_freep) char *empty_dir = NULL;
_cleanup_free_ char *j = NULL, *jj = NULL, *jjj = NULL;
assert_se(dir_is_empty_at(AT_FDCWD, "/proc") == 0);
assert_se(dir_is_empty_at(AT_FDCWD, "/icertainlydontexistdoi") == -ENOENT);
assert_se(dir_is_empty_at(AT_FDCWD, "/proc", /* ignore_hidden_or_backup= */ true) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, "/icertainlydontexistdoi", /* ignore_hidden_or_backup= */ true) == -ENOENT);
assert_se(mkdtemp_malloc("/tmp/emptyXXXXXX", &empty_dir) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) > 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0);
j = path_join(empty_dir, "zzz");
assert_se(j);
assert_se(touch(j) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0);
jj = path_join(empty_dir, "ppp");
assert_se(jj);
@ -173,13 +173,17 @@ TEST(dir_is_empty) {
assert_se(jjj);
assert_se(touch(jjj) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0);
assert_se(unlink(j) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) == 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0);
assert_se(unlink(jj) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) > 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) == 0);
assert_se(unlink(jjj) >= 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir) > 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ true) > 0);
assert_se(dir_is_empty_at(AT_FDCWD, empty_dir, /* ignore_hidden_or_backup= */ false) > 0);
}
static int intro(void) {