diff --git a/include/cosms-core/file.h b/include/cosms-core/file.h index f609ff4..45fd495 100644 --- a/include/cosms-core/file.h +++ b/include/cosms-core/file.h @@ -23,7 +23,7 @@ typedef enum { COSMS_FILE_FAILED_TO_WRITE = -8, } CosmsFileError; -CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned int *size); -CosmsFileError cosms_core_file_write(const char *path, const char *content, unsigned int size, bool override); +CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size); +CosmsFileError cosms_core_file_write(const char *path, const char *content, unsigned long long size, bool override); #endif diff --git a/src/file.c b/src/file.c index b3673af..670eb5f 100644 --- a/src/file.c +++ b/src/file.c @@ -9,6 +9,7 @@ #include "cosms-core/file.h" #include +#include #if defined(__GNUC__) #include @@ -16,9 +17,10 @@ #include #include #elif defined(_WIN32) +#include #endif -CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned int *size) { +CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size) { #if defined(__GNUC__) int file = open(path, O_RDONLY); if (file == -1) { @@ -55,7 +57,7 @@ CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned i while (remaining_bytes != 0) { int read_bytes = read(file, (*content) + (file_stat.st_size - remaining_bytes), remaining_bytes); if (read_bytes == -1) { - free(content); + free(*content); close(file); return COSMS_FILE_FAILED_TO_READ; } @@ -65,12 +67,68 @@ CosmsFileError cosms_core_file_read(const char *path, char **content, unsigned i close(file); #elif defined(_WIN32) + HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return COSMS_FILE_NOT_FOUND; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + return COSMS_FILE_NO_ACCESS; + + case ERROR_TOO_MANY_OPEN_FILES: + return COSMS_FILE_LIMIT_REACHED; + + default: + return COSMS_FILE_UNKOWN_ERROR; + } + } + + DWORD high_size; + DWORD low_size = GetFileSize(file, &high_size); + if (low_size == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + CloseHandle(file); + return COSMS_FILE_COULD_NOT_READ_SIZE; + } + + unsigned long long file_size = ((unsigned long long)high_size << 32) | low_size; + + *size = file_size; + *content = (char*)malloc((file_size + 1) * sizeof(char)); + if (content == NULL) { + CloseHandle(file); + return COSMS_FILE_FAILED_TO_ALLOCATE; + } + + unsigned long long remaining_bytes = file_size; + while (remaining_bytes != 0) { + DWORD bytes_to_read, read_bytes; + if (remaining_bytes > UINT_MAX) { + bytes_to_read = UINT_MAX; + } else { + bytes_to_read = (DWORD)remaining_bytes; + } + + if (!ReadFile(file, (*content) + (file_size - remaining_bytes), bytes_to_read, &read_bytes, NULL)) { + free(*content); + CloseHandle(file); + return COSMS_FILE_FAILED_TO_READ; + } + + remaining_bytes -= read_bytes; + } + + (*content)[file_size] = '\0'; + CloseHandle(file); #endif return COSMS_FILE_OK; } -CosmsFileError cosms_core_file_write(const char *path, const char *content, unsigned int size, bool override) { +CosmsFileError cosms_core_file_write(const char *path, const char *content, unsigned long long size, bool override) { #if defined(__GNUC__) int file; if (override) { @@ -109,6 +167,50 @@ CosmsFileError cosms_core_file_write(const char *path, const char *content, unsi close(file); #elif defined(_WIN32) + HANDLE file; + if (override) { + file = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + file = CreateFile(path, FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + + if (file == INVALID_HANDLE_VALUE) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return COSMS_FILE_NOT_FOUND; + + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + return COSMS_FILE_NO_ACCESS; + + case ERROR_TOO_MANY_OPEN_FILES: + return COSMS_FILE_LIMIT_REACHED; + + default: + return COSMS_FILE_UNKOWN_ERROR; + } + } + + unsigned long long remaining_bytes = size; + while (remaining_bytes != 0) { + DWORD bytes_to_write, written_bytes; + if (remaining_bytes > UINT_MAX) { + bytes_to_write = UINT_MAX; + } else { + bytes_to_write = (DWORD)remaining_bytes; + } + + if (!WriteFile(file, content + (size - remaining_bytes), bytes_to_write, &written_bytes, NULL)) { + CloseHandle(file); + return COSMS_FILE_FAILED_TO_WRITE; + } + + remaining_bytes -= written_bytes; + } + + CloseHandle(file); #endif return COSMS_FILE_OK; diff --git a/tests/main.c b/tests/main.c index b63a90b..0b3de1d 100644 --- a/tests/main.c +++ b/tests/main.c @@ -3,7 +3,7 @@ #include int main(void) { - unsigned int buffer_size; + unsigned long long buffer_size; char *buffer; CosmsFileError error = cosms_core_file_read("test.txt", &buffer, &buffer_size); if (error != COSMS_FILE_OK) { @@ -11,7 +11,7 @@ int main(void) { return -1; } - printf("File read with content:\n %s\n", buffer); + printf("File read with content:\n%s\n", buffer); char *temp_buffer = "Hello, World!"; error = cosms_core_file_write("write-file.txt", temp_buffer, 13, true);