diff --git a/include/cosms-core/file.h b/include/cosms-core/file.h index e4ee28e..09c7ec5 100644 --- a/include/cosms-core/file.h +++ b/include/cosms-core/file.h @@ -11,6 +11,10 @@ #include +#if defined(_WIN32) +#include +#endif + typedef enum { COSMS_CORE_FILE_OK = 0, COSMS_CORE_FILE_NOT_FOUND = -1, @@ -22,8 +26,29 @@ typedef enum { COSMS_CORE_FILE_FAILED_TO_READ = -7, COSMS_CORE_FILE_FAILED_TO_WRITE = -8, COSMS_CORE_FILE_STILL_OPEN = -9, + COSMS_CORE_FILE_INVALID_FILE = -10 } CosmsCoreFileError; +#define COSMS_CORE_FILE_LARGE 0x7FFFFFFF + +#define COSMS_CORE_FILE_MODE_READ (1u << 0) +#define COSMS_CORE_FILE_MODE_WRITE (1u << 1) +#define COSMS_CORE_FILE_MODE_APPEND (1u << 2) +#define COSMS_CORE_FILE_MODE_CREATE (1u << 3) + +struct cosms_core_file { + int mode; + + #if defined(__GNUC__) + int native_file; + #elif defined(_WIN32) + HANDLE native_file; + #endif +}; + +CosmsCoreFileError cosms_core_file_open(struct cosms_core_file *file, const char *path, int mode); +CosmsCoreFileError cosms_core_file_close(struct cosms_core_file *file); + CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size); CosmsCoreFileError cosms_core_file_write(const char *path, const char *content, unsigned long long size, bool override); diff --git a/src/file.c b/src/file.c index 523aa33..bdf18fe 100644 --- a/src/file.c +++ b/src/file.c @@ -19,14 +19,38 @@ #include #include #include -#elif defined(_WIN32) -#include #endif -CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size) { +CosmsCoreFileError cosms_core_file_open(struct cosms_core_file *file, const char *path, int mode) { + file->mode = mode; + #if defined(__GNUC__) - int file = open(path, O_RDONLY); - if (file == -1) { + int flags = 0; + if (mode & (COSMS_CORE_FILE_MODE_READ | COSMS_CORE_FILE_MODE_WRITE)) { + flags |= O_RDWR; + } else if (mode & COSMS_CORE_FILE_MODE_READ) { + flags |= O_RDONLY; + } else if (mode & COSMS_CORE_FILE_MODE_WRITE) { + flags |= (O_WRONLY | O_TRUNC); + } else if (mode & COSMS_CORE_FILE_MODE_APPEND) { + flags |= (O_WRONLY | O_APPEND); + } + + if (mode & COSMS_CORE_FILE_MODE_CREATE) { + flags |= O_CREAT; + } + + struct stat file_stat; + if (stat(path, &file_stat) != 0) { + return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; + } + + if (file_stat.st_size > COSMS_CORE_FILE_LARGE) { + flags |= O_LARGEFILE; + } + + file->native_file = open(path, flags); + if (file->native_file == -1) { switch(errno) { case ENOENT: return COSMS_CORE_FILE_NOT_FOUND; @@ -42,13 +66,105 @@ CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsign return COSMS_CORE_FILE_UNKOWN_ERROR; } } + #elif defined(_WIN32) + DWORD access_flags = 0; + DWORD create_flag = 0; + + if (mode & COSMS_CORE_FILE_MODE_READ) { + access_flags |= GENERIC_READ; + } + if (mode & COSMS_CORE_FILE_MODE_WRITE) { + access_flags |= GENERIC_WRITE; + } + + if (mode & COSMS_CORE_FILE_MODE_APPEND) { + access_flags |= GENERIC_WRITE; + create_flag = OPEN_ALWAYS; + } + + if (mode & COSMS_CORE_FILE_MODE_CREATE) { + create_flag = CREATE_ALWAYS; + } + + file->native_file = CreateFile(path, access_flags, 0, NULL, create_flag, FILE_ATTRIBUTE_NORMAL, NULL); + if (file->native_file == INVALID_HANDLE_VALUE) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return COSMS_CORE_FILE_NOT_FOUND; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + return COSMS_CORE_FILE_NO_ACCESS; + + case ERROR_TOO_MANY_OPEN_FILES: + return COSMS_CORE_FILE_LIMIT_REACHED; + + default: + return COSMS_CORE_FILE_UNKOWN_ERROR; + } + } + #endif + + return COSMS_CORE_FILE_OK; +} + +CosmsCoreFileError cosms_core_file_close(struct cosms_core_file *file) { + #if defined(__GNUC__) + int error = close(file->native_file); + if (error == -1) { + if (errno == EBADF) { + return COSMS_CORE_FILE_INVALID_FILE; + } + + return COSMS_CORE_FILE_UNKOWN_ERROR; + } + #elif defined(_WIN32) + BOOL error = CloseHandle(file); + if (error == 0) { + if (GetLastError() == ERROR_INVALID_HANDLE) { + return COSMS_CORE_FILE_INVALID_FILE; + } + + return COSMS_CORE_FILE_UNKOWN_ERROR; + } + #endif + + return COSMS_CORE_FILE_OK; +} + +CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size) { + #if defined(__GNUC__) struct stat file_stat; if (stat(path, &file_stat) != 0) { - close(file); return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } + int flags = O_RDONLY; + if (file_stat.st_size > COSMS_CORE_FILE_LARGE) { + flags |= O_LARGEFILE; + } + + int file = open(path, flags); + if (file == -1) { + switch(errno) { + case ENOENT: + return COSMS_CORE_FILE_NOT_FOUND; + + case EACCES: + return COSMS_CORE_FILE_NO_ACCESS; + + case EMFILE: + case ENFILE: + return COSMS_CORE_FILE_LIMIT_REACHED; + + default: + return COSMS_CORE_FILE_UNKOWN_ERROR; + } + } + if (size != NULL) { *size = file_stat.st_size; } @@ -147,13 +263,18 @@ CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsign CosmsCoreFileError cosms_core_file_write(const char *path, const char *content, unsigned long long size, bool override) { #if defined(__GNUC__) - int file; + int flags = O_WRONLY | O_CREAT; if (override) { - file = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + file |= O_TRUNC; } else { - file = open(path, O_WRONLY | O_CREAT | O_APPEND, 0644); + file |= O_APPEND; } + if (size > COSMS_CORE_FILE_LARGE) { + flags |= O_LARGEFILE; + } + + int file = open(path, flags, 0644); if (file == -1) { switch (errno) { case ENOENT: