From ee9132fdd37f20ff57047d692f9cff71068dd7e7 Mon Sep 17 00:00:00 2001 From: Michael Hardeman Date: Thu, 16 Mar 2023 17:50:39 -0400 Subject: [PATCH] Initial implementation of COPY and COPY_EACH_FILE_IN_DIR with example --- examples/.gitignore | 3 +- examples/copy.c | 33 ++++++++++++++ nobuild.h | 107 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 examples/copy.c diff --git a/examples/.gitignore b/examples/.gitignore index 9c39486..0dd24d6 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -2,4 +2,5 @@ string foreach logging file -pipe \ No newline at end of file +pipe +copy diff --git a/examples/copy.c b/examples/copy.c new file mode 100644 index 0000000..01f8721 --- /dev/null +++ b/examples/copy.c @@ -0,0 +1,33 @@ +#define NOBUILD_IMPLEMENTATION +#include "../nobuild.h" + +#define CFLAGS "-Wall", "-Wextra", "-std=c99", "-pedantic" + +#define DEMO(expr) \ + do { \ + INFO(#expr); \ + expr; \ + } while(0) + +void copy(const char *from, const char *to) +{ + COPY(from, to); +} + +void copy_each_file_in_dir(const char *from, const char *to) +{ + COPY_EACH_FILE_IN_DIR(from, to); +} + +int main(int argc, char **argv) +{ + MKDIRS(PATH("examples", "copy-test")); + + DEMO(copy(PATH("examples", "copy.c"), PATH("examples", "copy-test", "copy.c"))); + + DEMO(copy_each_file_in_dir("examples", PATH("examples", "copy-test"))); + + RM (PATH("examples", "copy-test")); + + return 0; +} \ No newline at end of file diff --git a/nobuild.h b/nobuild.h index 1f41c42..df3ae32 100644 --- a/nobuild.h +++ b/nobuild.h @@ -59,6 +59,7 @@ typedef HANDLE Fd; #define WIN32_LEAN_AND_MEAN #include "windows.h" + struct dirent { char d_name[MAX_PATH+1]; }; @@ -310,6 +311,38 @@ void path_rm(Cstr path); closedir(dir); \ } while(0) +int copy_file(Cstr from, Cstr to); +#define COPY(from, to) copy_file(from, to) + +#define COPY_EACH_FILE_IN_DIR(frompath, topath) \ + do { \ + struct dirent *dp = NULL; \ + DIR *dir = opendir(frompath); \ + if (dir == NULL) { \ + PANIC("could not open directory %s: %s", \ + frompath, strerror(errno)); \ + } \ + errno = 0; \ + while ((dp = readdir(dir))) { \ + const char *file = dp->d_name; \ + if (strcmp(file, ".") != 0 \ + && strcmp(file, "..") != 0) \ + { \ + copy_file( \ + PATH(frompath, file), \ + PATH(topath, file)); \ + } \ + \ + } \ + \ + if (errno > 0) { \ + PANIC("could not read directory %s: %s", \ + frompath, strerror(errno)); \ + } \ + \ + closedir(dir); \ + } while(0) + #if defined(__GNUC__) || defined(__clang__) // https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html #define NOBUILD_PRINTF_FORMAT(STRING_INDEX, FIRST_TO_CHECK) __attribute__ ((format (printf, STRING_INDEX, FIRST_TO_CHECK))) @@ -955,6 +988,7 @@ int path_exists(Cstr path) #endif } + int path_is_dir(Cstr path) { #ifdef _WIN32 @@ -1064,6 +1098,79 @@ void path_rm(Cstr path) } } +int copy_file(Cstr from, Cstr to) +{ + INFO("COPY: %s -> %s", from, to); +#ifdef _WIN32 + return CopyFileW(from, to, false); +#else + int fd_to, fd_from; + char buf[4096]; + ssize_t nread; + int saved_errno; + + fd_from = open(from, O_RDONLY); + if (fd_from < 0) + return -1; + + fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd_to < 0) { + WARN("file %s already exists. Overwriting", to); + path_rm(to); + + //retry opening + errno = 0; + fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd_to < 0) { + goto out_error; + } + } + + while (nread = read(fd_from, buf, sizeof buf), nread > 0) + { + char *out_ptr = buf; + ssize_t nwritten; + + do { + nwritten = write(fd_to, out_ptr, nread); + + if (nwritten >= 0) + { + nread -= nwritten; + out_ptr += nwritten; + } + else if (errno != EINTR) + { + goto out_error; + } + } while (nread > 0); + } + + if (nread == 0) + { + if (close(fd_to) < 0) + { + fd_to = -1; + goto out_error; + } + close(fd_from); + + return 0; // Success + } + + out_error: + saved_errno = errno; + + close(fd_from); + if (fd_to >= 0) + close(fd_to); + + errno = saved_errno; + return -1; +#endif +} + + int is_path1_modified_after_path2(const char *path1, const char *path2) { #ifdef _WIN32