mirror of
https://github.com/systemd/systemd.git
synced 2024-10-28 03:25:31 +03:00
tmpfiles: make sure "C" doesn't copy anything if the destination already exists
Previously it would recursively copy the entire tree in, and descend into subdirectories even if the destination already exists. Let's do what the documentation says and not do that. If files down the tree shall be copied too, they should get their own "C" lines.
This commit is contained in:
parent
19f3934057
commit
e156347e04
@ -225,7 +225,17 @@ 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 don't exist yet.</para></listitem>
|
||||
<listitem><para>Recursively
|
||||
copy a file or directory, if
|
||||
the destination files or
|
||||
directories don't exist
|
||||
yet. Note that this command
|
||||
will not descend into
|
||||
subdirectories if the
|
||||
destination directory already
|
||||
exists, instead the entire
|
||||
copy operation is
|
||||
skipped.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -59,12 +59,8 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (symlinkat(target, dt, to) < 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
|
||||
if (symlinkat(target, dt, to) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
return -errno;
|
||||
@ -85,12 +81,8 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
|
||||
return -errno;
|
||||
|
||||
fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
|
||||
if (fdt < 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
|
||||
if (fdt < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = copy_bytes(fdf, fdt);
|
||||
if (r < 0) {
|
||||
@ -123,12 +115,8 @@ static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt,
|
||||
assert(to);
|
||||
|
||||
r = mkfifoat(dt, to, st->st_mode & 07777);
|
||||
if (r < 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
r = -errno;
|
||||
@ -147,12 +135,8 @@ static int fd_copy_node(int df, const char *from, const struct stat *st, int dt,
|
||||
assert(to);
|
||||
|
||||
r = mknodat(dt, to, st->st_mode, st->st_rdev);
|
||||
if (r < 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
r = -errno;
|
||||
@ -163,7 +147,7 @@ static int fd_copy_node(int df, const char *from, const struct stat *st, int dt,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int fd_copy_directory(int df, const char *from, const struct stat *st, int dt, const char *to, dev_t original_device) {
|
||||
static int fd_copy_directory(int df, const char *from, const struct stat *st, int dt, const char *to, dev_t original_device, bool merge) {
|
||||
_cleanup_close_ int fdf = -1, fdt = -1;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
@ -186,7 +170,7 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in
|
||||
r = mkdirat(dt, to, st->st_mode & 07777);
|
||||
if (r >= 0)
|
||||
created = true;
|
||||
else if (errno == EEXIST)
|
||||
else if (errno == EEXIST && merge)
|
||||
created = false;
|
||||
else
|
||||
return -errno;
|
||||
@ -219,7 +203,7 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in
|
||||
if (S_ISREG(buf.st_mode))
|
||||
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
else if (S_ISDIR(buf.st_mode))
|
||||
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device);
|
||||
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
|
||||
else if (S_ISLNK(buf.st_mode))
|
||||
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
|
||||
else if (S_ISFIFO(buf.st_mode))
|
||||
@ -229,6 +213,9 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in
|
||||
else
|
||||
q = -ENOTSUP;
|
||||
|
||||
if (q == -EEXIST && merge)
|
||||
q = 0;
|
||||
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
@ -236,7 +223,7 @@ static int fd_copy_directory(int df, const char *from, const struct stat *st, in
|
||||
return r;
|
||||
}
|
||||
|
||||
int copy_tree(const char *from, const char *to) {
|
||||
int copy_tree(const char *from, const char *to, bool merge) {
|
||||
struct stat st;
|
||||
|
||||
assert(from);
|
||||
@ -248,7 +235,7 @@ int copy_tree(const char *from, const char *to) {
|
||||
if (S_ISREG(st.st_mode))
|
||||
return fd_copy_regular(AT_FDCWD, from, &st, AT_FDCWD, to);
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev);
|
||||
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
return fd_copy_symlink(AT_FDCWD, from, &st, AT_FDCWD, to);
|
||||
else if (S_ISFIFO(st.st_mode))
|
||||
|
@ -22,5 +22,5 @@
|
||||
***/
|
||||
|
||||
int copy_file(const char *from, const char *to, int flags, mode_t mode);
|
||||
int copy_tree(const char *from, const char *to);
|
||||
int copy_tree(const char *from, const char *to, bool merge);
|
||||
int copy_bytes(int fdf, int fdt);
|
||||
|
@ -667,10 +667,29 @@ static int create_item(Item *i) {
|
||||
break;
|
||||
|
||||
case COPY_FILES:
|
||||
r = copy_tree(i->argument, i->path);
|
||||
r = copy_tree(i->argument, i->path, false);
|
||||
if (r < 0) {
|
||||
log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
|
||||
return r;
|
||||
struct stat a, b;
|
||||
|
||||
if (r != -EEXIST) {
|
||||
log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (stat(i->argument, &a) < 0) {
|
||||
log_error("stat(%s) failed: %m", i->argument);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (stat(i->path, &b) < 0) {
|
||||
log_error("stat(%s) failed: %m", i->path);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if ((a.st_mode ^ b.st_mode) & S_IFMT) {
|
||||
log_debug("Can't copy to %s, file exists already and is of different type", i->path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = item_set_perms(i, i->path);
|
||||
@ -694,19 +713,21 @@ static int create_item(Item *i) {
|
||||
r = mkdir_label(i->path, i->mode);
|
||||
}
|
||||
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_error("Failed to create directory %s: %s", i->path, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
if (r < 0) {
|
||||
if (r != -EEXIST) {
|
||||
log_error("Failed to create directory %s: %s", i->path, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
if (stat(i->path, &st) < 0) {
|
||||
log_error("stat(%s) failed: %m", i->path);
|
||||
return -errno;
|
||||
}
|
||||
if (stat(i->path, &st) < 0) {
|
||||
log_error("stat(%s) failed: %m", i->path);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
log_error("%s is not a directory.", i->path);
|
||||
return -EEXIST;
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
log_debug("%s already exists and is not a directory.", i->path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = item_set_perms(i, i->path);
|
||||
|
Loading…
Reference in New Issue
Block a user