Commit 4639d19eaf1f2fb055f4fcec251b85efa200ea8f

Thomas de Grivel 2023-10-23T15:18:31

replace system("cp ...") with file_copy

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);