641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier/***
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier This file is part of systemd
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Copyright 2014 Ronny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier systemd is free software; you can redistribute it and/or modify it
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier under the terms of the GNU Lesser General Public License as published by
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier the Free Software Foundation; either version 2.1 of the License, or
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier (at your option) any later version.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier systemd is distributed in the hope that it will be useful, but
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier WITHOUT ANY WARRANTY; without even the implied warranty of
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Lesser General Public License for more details.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier You should have received a copy of the GNU Lesser General Public License
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier***/
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include <unistd.h>
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "copy.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "fileio.h"
f4f15635ec05293ffcc83a5b39f624bbabbd8fd0Lennart Poettering#include "fs-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "macro.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "mkdir.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "path-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "rm-rf.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "strv.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierstatic void test_copy_file(void) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier _cleanup_free_ char *buf = NULL;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char fn[] = "/tmp/test-copy_file.XXXXXX";
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char fn_copy[] = "/tmp/test-copy_file.XXXXXX";
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier size_t sz = 0;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier int fd;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(fd >= 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier close(fd);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier fd = mkostemp_safe(fn_copy, O_RDWR|O_CLOEXEC);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(fd >= 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier close(fd);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
f2068bcce01db31cdc9422f44185f3b49c04d2ceLennart Poettering assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(read_full_file(fn_copy, &buf, &sz) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(streq(buf, "foo bar bar bar foo\n"));
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(sz == 20);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier unlink(fn);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier unlink(fn_copy);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poetteringstatic void test_copy_file_fd(void) {
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering char in_fn[] = "/tmp/test-copy-file-fd-XXXXXX";
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering char out_fn[] = "/tmp/test-copy-file-fd-XXXXXX";
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering _cleanup_close_ int in_fd = -1, out_fd = -1;
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering char text[] = "boohoo\nfoo\n\tbar\n";
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering char buf[64] = {0};
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering in_fd = mkostemp_safe(in_fn, O_RDWR);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(in_fd >= 0);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering out_fd = mkostemp_safe(out_fn, O_RDWR);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(out_fd >= 0);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0);
7430ec6ac08f2c0416d9f806964c46b30f3862b2Lennart Poettering assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0);
7430ec6ac08f2c0416d9f806964c46b30f3862b2Lennart Poettering assert_se(copy_file_fd(in_fn, out_fd, true) >= 0);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert_se(streq(buf, text));
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering unlink(in_fn);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering unlink(out_fn);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering}
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierstatic void test_copy_tree(void) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char original_dir[] = "/tmp/test-copy_tree/";
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char copy_dir[] = "/tmp/test-copy_tree-copy/";
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char **links = STRV_MAKE("link", "file",
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "link2", "dir1/file");
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier char **p, **link;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier STRV_FOREACH(p, files) {
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *f = strjoina(original_dir, *p);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(mkdir_parents(f, 0755) >= 0);
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier }
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier STRV_FOREACH_PAIR(link, p, links) {
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *f = strjoina(original_dir, *p);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *l = strjoina(original_dir, *link);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(mkdir_parents(l, 0755) >= 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(symlink(f, l) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier }
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(copy_tree(original_dir, copy_dir, true) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier STRV_FOREACH(p, files) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier _cleanup_free_ char *buf = NULL;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier size_t sz = 0;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *f = strjoina(copy_dir, *p);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(access(f, F_OK) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(read_full_file(f, &buf, &sz) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(streq(buf, "file\n"));
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier }
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier STRV_FOREACH_PAIR(link, p, links) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier _cleanup_free_ char *target = NULL;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *f = strjoina(original_dir, *p);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *l = strjoina(copy_dir, *link);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(readlink_and_canonicalize(l, &target) == 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(path_equal(f, target));
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier }
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(copy_tree(original_dir, copy_dir, false) < 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmekstatic void test_copy_bytes(void) {
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek _cleanup_close_pair_ int pipefd[2] = {-1, -1};
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek _cleanup_close_ int infd = -1;
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek int r, r2;
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek char buf[1024], buf2[1024];
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov infd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov if (infd < 0)
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov infd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(infd >= 0);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(pipe2(pipefd, O_CLOEXEC) == 0);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
59f448cf15f94bc5ebfd5b254de6f2441d02fbecLennart Poettering r = copy_bytes(infd, pipefd[1], (uint64_t) -1, false);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r == 0);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = read(pipefd[0], buf, sizeof(buf));
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r >= 0);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(lseek(infd, 0, SEEK_SET) == 0);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r2 = read(infd, buf2, sizeof(buf2));
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r == r2);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(strneq(buf, buf2, r));
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek /* test copy_bytes with invalid descriptors */
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = copy_bytes(pipefd[0], pipefd[0], 1, false);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r == -EBADF);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = copy_bytes(pipefd[1], pipefd[1], 1, false);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r == -EBADF);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = copy_bytes(pipefd[1], infd, 1, false);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek assert_se(r == -EBADF);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek}
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierint main(int argc, char *argv[]) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier test_copy_file();
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering test_copy_file_fd();
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier test_copy_tree();
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek test_copy_bytes();
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return 0;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}