mirror of
https://github.com/systemd/systemd.git
synced 2025-03-22 06:50:18 +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:
commit
477fd8e886
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user