summaryrefslogtreecommitdiff
path: root/src/bindings.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-01-03 20:59:16 -0600
committersanine <sanine.not@pm.me>2022-01-03 20:59:16 -0600
commit5830f684ba172664df43eee26636e99e5a228028 (patch)
tree959fe4bd5545e40ef0403432cad535088abb6796 /src/bindings.c
parent7db6401dfb0604e92946ac4f7c76d541498e6ebb (diff)
add create_directory() and copy_file()
Diffstat (limited to 'src/bindings.c')
-rw-r--r--src/bindings.c157
1 files changed, 157 insertions, 0 deletions
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 <string.h>
#include <lua.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#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;
+}