diff options
Diffstat (limited to 'src/bindings.c')
-rw-r--r-- | src/bindings.c | 157 |
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; +} |