From 5830f684ba172664df43eee26636e99e5a228028 Mon Sep 17 00:00:00 2001 From: sanine Date: Mon, 3 Jan 2022 20:59:16 -0600 Subject: add create_directory() and copy_file() --- src/argent.c | 4 +- src/bindings.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bindings.h | 4 ++ 3 files changed, 164 insertions(+), 1 deletion(-) diff --git a/src/argent.c b/src/argent.c index c4738d4..ae3a717 100644 --- a/src/argent.c +++ b/src/argent.c @@ -34,7 +34,9 @@ int main(int argc, char **argv) hs_create_table (L, hs_str_cfunc("markdown", markdown), - hs_str_cfunc("scanDirectory", scan_directory) + hs_str_cfunc("scanDirectory", scan_directory), + hs_str_cfunc("createDirectory", create_directory), + hs_str_cfunc("copyFile", copy_file) ); lua_setglobal(L, "argent"); diff --git a/src/bindings.c b/src/bindings.c index 2988685..8e7d4d5 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -2,8 +2,11 @@ #include #include #include +#include +#include #include #include +#include #include "honeysuckle.h" #include "md4c-html.h" @@ -164,3 +167,157 @@ static struct dirent *read_dir(lua_State *L, DIR *directory) return entry; } + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static const char* mkdir_error_string() +{ + switch(errno) { + case EACCES: + return "Permission denied"; + + case EEXIST: + return "A file with that name already exists"; + + case EMLINK: + return "The parent directory is full"; + + case ENOSPC: + return "The file system is full"; + + case EROFS: + return "The parent directory is read-only"; + + default: + return "unknown error"; + } +} + +int create_directory(lua_State *L) +{ + char *dir_name; + hs_parse_args(L, hs_str(dir_name)); + + mode_t mode = S_IRWXU | S_IRWXG | (S_IROTH | S_IXOTH); // u+rwx, g+rwx, a+rx + + int error = mkdir(dir_name, mode); + if (error) { + argent_log(ERROR, "failed to create directory '%s': %s", + dir_name, mkdir_error_string()); + hs_throw_error(L, "failed to create directory '%s': %s", + dir_name, mkdir_error_string()); + } + + return 0; +} + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +static const char* open_error_string() +{ + switch (errno) { + case EACCES: + return "Permission denied"; + + case EBUSY: + return "Device busy"; + + case EDQUOT: + return "User cannot create new inodes"; + + case EEXIST: + return "File exists"; + + case EFAULT: + return "Pathname points outside your accessible address space"; + + case EINTR: + return "Operation interrupted"; + + case EINVAL: + return "Attempted an invalid operation"; + + case ELOOP: + return "Too many symbolic links encountered in resolving the pathname"; + + case EMFILE: + return "The process has too many open files"; + + case ENAMETOOLONG: + return "The pathname was too long"; + + case ENOMEM: + return "Insufficient kernel memory available"; + + case ENOSPC: + return "No space available on the device"; + + case EOVERFLOW: + return "File is too large to open"; + + case ETXTBSY: + return "File is busy"; + + default: + return "Other error"; + } +} + +int copy_file(lua_State *L) +{ + char *source_name, *dest_name; + hs_parse_args(L, hs_str(source_name), hs_str(dest_name)); + + int source_fd, dest_fd; + + source_fd = open(source_name, 0); + if (source_fd == -1) { + argent_log(ERROR, "failed to open file '%s': %s", + source_name, open_error_string()); + hs_throw_error(L, "failed to open file '%s': %s", + source_name, open_error_string()); + } + + struct stat source_stat; + int error = fstat(source_fd, &source_stat); + if (error) { + close(source_fd); + argent_log(ERROR, "failed to stat '%s': %s", + source_name, open_error_string()); + hs_throw_error(L, "failed to stat '%s': %s", + source_name, open_error_string()); + } + mode_t dest_mode = source_stat.st_mode; + dest_fd = creat(dest_name, dest_mode); + if (dest_fd == -1) { + close(source_fd); + argent_log(ERROR, "failed to open file '%s': %s", + dest_name, open_error_string()); + hs_throw_error(L, "failed to open file '%s': %s", + dest_name, open_error_string()); + } + + unsigned char buffer[256]; + size_t buffer_size = sizeof(unsigned char) * 256; + ssize_t bytes_read; + while ( (bytes_read = read(source_fd, buffer, buffer_size)) == buffer_size ) { + write(dest_fd, buffer, buffer_size); + } + + if (bytes_read == -1) { + argent_log(ERROR, "failed to write to file '%s'", dest_name); + close(source_fd); + close(dest_fd); + hs_throw_error(L, "failed to write to file '%s'", dest_name); + } + else { + write(dest_fd, buffer, bytes_read); + } + + close(source_fd); + close(dest_fd); + + return 0; +} diff --git a/src/bindings.h b/src/bindings.h index 853f0c0..847baa7 100644 --- a/src/bindings.h +++ b/src/bindings.h @@ -9,4 +9,8 @@ int markdown(lua_State *L); // and the other containing filenames for all regular files int scan_directory(lua_State *L); +int create_directory(lua_State *L); + +int copy_file(lua_State *L); + #endif -- cgit v1.2.1