1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-28 03:25:27 +03:00

Merge pull request #11345 from kirbyfan64/tmpfiles-c-empty

tmpfiles: Make C still copy if the destination directory is empty
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-01-15 16:54:19 +01:00 committed by GitHub
commit 477fd8e886
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 23 deletions

View File

@ -282,11 +282,11 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<varlistentry>
<term><varname>C</varname></term>
<listitem><para>Recursively copy a file or directory, if the
destination files or directories do not exist yet. Note that
this command will not descend into subdirectories if the
destination directory already exists. Instead, the entire
copy operation is skipped. If the argument is omitted, files
from the source directory
destination files or directories do not exist yet or the
destination directory is empty. Note that this command will not
descend into subdirectories if the destination directory already
exists and is not empty. Instead, the entire copy operation is
skipped. If the argument is omitted, files from the source directory
<filename>/usr/share/factory/</filename> with the same name
are copied. Does not follow symlinks.</para></listitem>
</varlistentry>

View File

@ -24,6 +24,7 @@
#include "macro.h"
#include "missing.h"
#include "mountpoint-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@ -501,7 +502,7 @@ static int fd_copy_directory(
_cleanup_close_ int fdf = -1, fdt = -1;
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
bool created;
bool exists, created;
int r;
assert(st);
@ -522,13 +523,26 @@ static int fd_copy_directory(
return -errno;
fdf = -1;
r = mkdirat(dt, to, st->st_mode & 07777);
if (r >= 0)
created = true;
else if (errno == EEXIST && (copy_flags & COPY_MERGE))
exists = false;
if (copy_flags & COPY_MERGE_EMPTY) {
r = dir_is_empty_at(dt, to);
if (r < 0 && r != -ENOENT)
return r;
else if (r == 1)
exists = true;
}
if (exists)
created = false;
else
return -errno;
else {
r = mkdirat(dt, to, st->st_mode & 07777);
if (r >= 0)
created = true;
else if (errno == EEXIST && (copy_flags & COPY_MERGE))
created = false;
else
return -errno;
}
fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fdt < 0)

View File

@ -9,10 +9,11 @@
#include <sys/types.h>
typedef enum CopyFlags {
COPY_REFLINK = 1 << 0, /* Try to reflink */
COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
COPY_REFLINK = 1 << 0, /* Try to reflink */
COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */
COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */
COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
} CopyFlags;
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);

View File

@ -67,13 +67,22 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
int dir_is_empty_at(int dir_fd, const char *path) {
_cleanup_close_ int fd = -1;
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
d = opendir(path);
if (path)
fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
else
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0)
return -errno;
d = fdopendir(fd);
if (!d)
return -errno;
fd = -1;
FOREACH_DIRENT(de, d, return -errno)
return 0;

View File

@ -15,7 +15,10 @@ 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(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;

View File

@ -1463,7 +1463,7 @@ static int copy_files(Item *i) {
dfd, bn,
i->uid_set ? i->uid : UID_INVALID,
i->gid_set ? i->gid : GID_INVALID,
COPY_REFLINK);
COPY_REFLINK | COPY_MERGE_EMPTY);
if (r < 0) {
struct stat a, b;

View File

@ -6,8 +6,8 @@
set -e
set -x
rm -fr /tmp/{d,D,e}
mkdir /tmp/{d,D,e}
rm -fr /tmp/{C,d,D,e}
mkdir /tmp/{C,d,D,e}
#
# 'd'
@ -93,3 +93,30 @@ test $(stat -c %U:%G:%a /tmp/e/3/d2) = "daemon:daemon:755"
test -f /tmp/e/3/f1
test $(stat -c %U:%G:%a /tmp/e/3/f1) = "root:root:644"
#
# 'C'
#
mkdir /tmp/C/{1,2,3}-origin
touch /tmp/C/{1,2,3}-origin/f1
chmod 755 /tmp/C/{1,2,3}-origin/f1
mkdir /tmp/C/{2,3}
touch /tmp/C/3/f1
systemd-tmpfiles --create - <<EOF
C /tmp/C/1 0755 daemon daemon - /tmp/C/1-origin
C /tmp/C/2 0755 daemon daemon - /tmp/C/2-origin
EOF
test -d /tmp/C/1
test $(stat -c %U:%G:%a /tmp/C/1/f1) = "daemon:daemon:755"
test -d /tmp/C/2
test $(stat -c %U:%G:%a /tmp/C/2/f1) = "daemon:daemon:755"
! systemd-tmpfiles --create - <<EOF
C /tmp/C/3 0755 daemon daemon - /tmp/C/3-origin
EOF
test $(stat -c %U:%G:%a /tmp/C/3/f1) = "root:root:644"