diff --git a/libc3/file.c b/libc3/file.c
index 1452254..97b2c90 100644
--- a/libc3/file.c
+++ b/libc3/file.c
@@ -11,11 +11,59 @@
* THIS SOFTWARE.
*/
#include <assert.h>
+#include <fcntl.h>
#include <err.h>
+#include <errno.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "file.h"
#include "timespec.h"
+int file_copy (const char *from, const char *to)
+{
+ char buf[4096];
+ int fd_from = -1;
+ int fd_to = -1;
+ ssize_t r;
+ int saved_errno;
+
+ if ((fd_from = open(from, O_RDONLY)) < 0) {
+ warn("cp: %s", from);
+ return -1;
+ }
+ if ((fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) {
+ warn("cp: %s", to);
+ goto error;
+ }
+ while ((r = read(fd_from, buf, sizeof buf)) > 0) {
+ char *out = buf;
+ ssize_t w;
+ do {
+ if ((w = write(fd_to, out, r)) >= 0) {
+ r -= w;
+ out += w;
+ }
+ else if (errno != EINTR)
+ goto error;
+ } while (r > 0);
+ }
+ if (r == 0) {
+ if (close(fd_to) < 0) {
+ fd_to = -1;
+ goto error;
+ }
+ close(fd_from);
+ return 0;
+ }
+ error:
+ saved_errno = errno;
+ close(fd_from);
+ if (fd_to >= 0)
+ close(fd_to);
+ errno = saved_errno;
+ return -1;
+}
+
s_tag * file_mtime (const s_str *path, s_tag *dest)
{
struct stat sb;
diff --git a/libc3/file.h b/libc3/file.h
index d50dd8b..bb65aab 100644
--- a/libc3/file.h
+++ b/libc3/file.h
@@ -22,6 +22,7 @@
#include "types.h"
/* Observers */
+int file_copy (const char *from, const char *to);
s_tag * file_mtime (const s_str *path, s_tag *dest);
#endif /* FILE_H */
diff --git a/test/facts_test.c b/test/facts_test.c
index 127e2e0..7bd21d5 100644
--- a/test/facts_test.c
+++ b/test/facts_test.c
@@ -15,6 +15,7 @@
#include "../libc3/buf.h"
#include "../libc3/compare.h"
#include "../libc3/facts.h"
+#include "../libc3/file.h"
#include "../libc3/log.h"
#include "fact_test.h"
#include "test.h"
@@ -457,14 +458,12 @@ TEST_CASE(facts_open_file)
"-0x10000000000000001",
NULL
};
- sw r;
s_fact fact;
s_facts facts;
s_str path;
- if ((r = system("cp facts_test_open_file.1.in.facts facts_test_open_file.1.facts")) < 0)
- err(1, "%s:%i: cp", __FILE__, __LINE__);
- if (r > 0)
- errx(1, "%s:%i: cp", __FILE__, __LINE__);
+ if (file_copy("facts_test_open_file.1.in.facts",
+ "facts_test_open_file.1.facts"))
+ err(1, "%s:%i: file_copy", __FILE__, __LINE__);
facts_init(&facts);
str_init_1(&path, NULL, "facts_test_open_file.1.facts");
TEST_EQ(facts_open_file(&facts, &path), 760);
@@ -492,10 +491,9 @@ TEST_CASE(facts_open_file)
if (g_test_last_ok)
unlink("facts_test_open_file.1.facts");
facts_init(&facts);
- if ((r = system("cp facts_test_open_file.2.in.facts facts_test_open_file.2.facts")) < 0)
- err(1, "%s:%i: cp", __FILE__, __LINE__);
- if (r > 0)
- errx(1, "%s:%i: cp", __FILE__, __LINE__);
+ if (file_copy("facts_test_open_file.2.in.facts",
+ "facts_test_open_file.2.facts"))
+ err(1, "%s:%i: file_copy", __FILE__, __LINE__);
str_init_1(&path, NULL, "facts_test_open_file.2.facts");
TEST_EQ(facts_open_file(&facts, &path), 1523);
TEST_EQ(facts_count(&facts), 46);
@@ -520,10 +518,9 @@ TEST_CASE(facts_open_file)
if (g_test_last_ok)
unlink("facts_test_open_file.2.facts");
facts_init(&facts);
- if ((r = system("cp facts_test_open_file.3.in.facts facts_test_open_file.3.facts")) < 0)
- err(1, "%s:%i: cp", __FILE__, __LINE__);
- if (r > 0)
- errx(1, "%s:%i: cp", __FILE__, __LINE__);
+ if (file_copy("facts_test_open_file.3.in.facts",
+ "facts_test_open_file.3.facts"))
+ err(1, "%s:%i: file_copy", __FILE__, __LINE__);
str_init_1(&path, NULL, "facts_test_open_file.3.facts");
TEST_EQ(facts_open_file(&facts, &path), 1550);
TEST_EQ(facts_count(&facts), 0);