diff options
Diffstat (limited to 'src/blogc-make/exec-native.c')
-rw-r--r-- | src/blogc-make/exec-native.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/blogc-make/exec-native.c b/src/blogc-make/exec-native.c new file mode 100644 index 0000000..32874b4 --- /dev/null +++ b/src/blogc-make/exec-native.c @@ -0,0 +1,161 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <fcntl.h> +#include <unistd.h> +#include <libgen.h> +#include <errno.h> +#include "../common/file.h" +#include "../common/utils.h" +#include "exec-native.h" +#include "ctx.h" + + +int +bm_exec_native_cp(bm_filectx_t *source, bm_filectx_t *dest, bool verbose) +{ + if (verbose) + printf("Copying '%s' to '%s'\n", source->path, dest->path); + else + printf(" COPY %s\n", dest->short_path); + fflush(stdout); + + char *fname = bc_strdup(dest->path); + for (char *tmp = fname; *tmp != '\0'; tmp++) { + if (*tmp != '/' && *tmp != '\\') + continue; + char bkp = *tmp; + *tmp = '\0'; + if ((strlen(fname) > 0) && + (-1 == mkdir(fname, 0777)) && + (errno != EEXIST)) + { + fprintf(stderr, "blogc-make: error: failed to create output " + "directory (%s): %s\n", fname, strerror(errno)); + free(fname); + exit(2); + } + *tmp = bkp; + } + free(fname); + + int fd_from = open(source->path, O_RDONLY); + if (fd_from < 0) { + fprintf(stderr, "blogc-make: error: failed to open source file to copy " + " (%s): %s\n", source->path, strerror(errno)); + return 3; + } + + int fd_to = open(dest->path, O_WRONLY | O_CREAT, 0666); + if (fd_to < 0) { + fprintf(stderr, "blogc-make: error: failed to open destination file to " + "copy (%s): %s\n", dest->path, strerror(errno)); + close(fd_from); + return 3; + } + + ssize_t nread; + char buffer[BC_FILE_CHUNK_SIZE]; + while (0 < (nread = read(fd_from, buffer, BC_FILE_CHUNK_SIZE))) { + char *out_ptr = buffer; + do { + ssize_t nwritten = write(fd_to, out_ptr, nread); + if (nwritten == -1) { + fprintf(stderr, "blogc-make: error: failed to write to " + "destination file (%s): %s\n", dest->path, strerror(errno)); + close(fd_from); + close(fd_to); + return 3; + } + nread -= nwritten; + out_ptr += nwritten; + } while (nread > 0); + } + + return 0; +} + + +int +bm_exec_native_rm(bm_filectx_t *dest, bool verbose) +{ + if (verbose) + printf("Removing file '%s'\n", dest->path); + else + printf(" CLEAN %s\n", dest->short_path); + fflush(stdout); + + if (0 != unlink(dest->path)) { + fprintf(stderr, "blogc-make: error: failed to remove file (%s): %s\n", + dest->path, strerror(errno)); + return 3; + } + + int rv = 0; + + char *short_path = bc_strdup(dest->short_path); + char *path = bc_strdup(dest->path); + + char *dir_short = dirname(short_path); + char *dir = dirname(path); + + while (0 != strcmp(dir_short, ".")) { + + DIR *d = opendir(dir); + if (d == NULL) { + fprintf(stderr, "error: failed to open directory (%s): %s\n", + dir, strerror(errno)); + rv = 3; + break; + } + + struct dirent *e; + size_t count = 0; + while (NULL != (e = readdir(d))) { + if ((0 == strcmp(e->d_name, ".")) || (0 == strcmp(e->d_name, ".."))) + continue; + count++; + break; + } + + if (0 != closedir(d)) { + fprintf(stderr, "error: failed to close directory (%s): %s\n", + dir, strerror(errno)); + rv = 3; + break; + } + + if (count == 0) { + if (verbose) { + printf("Removing directory '%s'\n", dir); + fflush(stdout); + } + if (0 != rmdir(dir)) { + fprintf(stderr, "error: failed to remove directory(%s): %s\n", + dir, strerror(errno)); + rv = 3; + break; + } + } + + dir_short = dirname(dir_short); + dir = dirname(dir); + } + + free(short_path); + free(path); + + return rv; +} |