diff --git a/include/cosms-core/file.h b/include/cosms-core/file.h index eef6e6b..ef6a508 100644 --- a/include/cosms-core/file.h +++ b/include/cosms-core/file.h @@ -24,7 +24,8 @@ 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 + COSMS_CORE_FILE_INVALID_FILE = -10, + COSMS_CORE_FILE_INVALID_OPERATION = -11 } CosmsCoreFileError; #define COSMS_CORE_FILE_LARGE 0x7FFFFFFF @@ -49,8 +50,11 @@ CosmsCoreFileError cosms_core_file_close(struct cosms_core_file *file); CosmsCoreFileError cosms_core_file_get_size(struct cosms_core_file *file, unsigned long long *size); -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, int mode); +CosmsCoreFileError cosms_core_file_read(struct cosms_core_file *file, char **buffer, unsigned int bytes_to_read, unsigned int *bytes_read); +CosmsCoreFileError cosms_core_file_read_all(struct cosms_core_file *file, char **buffer, unsigned long long *bytes_read); + +CosmsCoreFileError cosms_core_file_write(struct cosms_core_file *file, char *buffer, unsigned int bytes_to_write, unsigned int *bytes_written); +CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char *buffer, unsigned long long bytes_to_write); CosmsCoreFileError cosms_core_file_delete(const char *path); diff --git a/src/file.c b/src/file.c index 37cd10e..8be8ac1 100644 --- a/src/file.c +++ b/src/file.c @@ -164,228 +164,172 @@ CosmsCoreFileError cosms_core_file_get_size(struct cosms_core_file *file, unsign return COSMS_CORE_FILE_OK; } -CosmsCoreFileError cosms_core_file_read(const char *path, char **content, unsigned long long *size) { +CosmsCoreFileError cosms_core_file_read(struct cosms_core_file *file, char **buffer, unsigned int bytes_to_read, unsigned int *bytes_read) { + if ((file->mode & COSMS_CORE_FILE_MODE_READ) == 0) { + return COSMS_CORE_FILE_INVALID_OPERATION; + } + + #if defined(__GNUC__) + int read_bytes = read(file->native_file, *buffer, bytes_to_read); + if (read_bytes == -1) { + return COSMS_CORE_FILE_FAILED_TO_READ; + } + + if (bytes_read != NULL) { + (*bytes_read) = read_bytes; + } + #elif defined(_WIN32) + if (ReadFile(file->native_file, *buffer, bytes_to_read, (LPDWORD)bytes_read, NULL) == 0) { + return COSMS_CORE_FILE_FAILED_TO_READ; + } + #endif + + buffer[bytes_to_read] = '\0'; + return COSMS_CORE_FILE_OK; +} + +CosmsCoreFileError cosms_core_file_read_all(struct cosms_core_file *file, char **buffer, unsigned long long *bytes_read) { + if ((file->mode & COSMS_CORE_FILE_MODE_READ) == 0) { + return COSMS_CORE_FILE_INVALID_OPERATION; + } + #if defined(__GNUC__) struct stat file_stat; - if (stat(path, &file_stat) != 0) { + if (fstat(file->native_file, &file_stat) != 0) { return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } - int flags = O_RDONLY; - if (file_stat.st_size > COSMS_CORE_FILE_LARGE) { - flags |= O_LARGEFILE; + if (bytes_read != NULL) { + (*bytes_read) = file_stat.st_size; } - 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; - } - - *content = (char*)malloc((file_stat.st_size + 1) * sizeof(char)); - if (content == NULL) { - close(file); + (*buffer) = (char*)malloc((file_stat.st_size + 1) * sizeof(char)); + if ((*buffer) == NULL) { return COSMS_CORE_FILE_FAILED_TO_ALLOCATE; } - + unsigned long long remaining_bytes = file_stat.st_size; while (remaining_bytes != 0) { - unsigned int bytes_to_read; + unsigned int current_bytes_to_read; if (remaining_bytes > UINT_MAX) { - bytes_to_read = UINT_MAX; + current_bytes_to_read = UINT_MAX; } else { - bytes_to_read = (unsigned int)remaining_bytes; + current_bytes_to_read = (unsigned int)remaining_bytes; } - int read_bytes = read(file, (*content) + (file_stat.st_size - remaining_bytes), bytes_to_read); + int read_bytes = read(file, (*buffer) + (file_stat.st_size - remaining_bytes), current_bytes_to_read); if (read_bytes == -1) { - free(*content); - close(file); + free(*buffer); return COSMS_CORE_FILE_FAILED_TO_READ; } remaining_bytes -= read_bytes; } - - (*content)[file_stat.st_size] = '\0'; - close(file); + + (*buffer)[file_stat.st_size] = '\0'; #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_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; - } - } - DWORD high_size; - DWORD low_size = GetFileSize(file, &high_size); + DWORD low_size = GetFileSize(file->native_file, &high_size); if (low_size == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - CloseHandle(file); return COSMS_CORE_FILE_COULD_NOT_READ_SIZE; } unsigned long long file_size = ((unsigned long long)high_size << 32) | low_size; - if (size != NULL) { - *size = file_size; + if (bytes_read != NULL) { + (*bytes_read) = file_size; } - *content = (char*)malloc((file_size + 1) * sizeof(char)); - if (content == NULL) { - CloseHandle(file); + (*buffer) = (char*)malloc((file_size + 1) * sizeof(char)); + if ((*buffer) == NULL) { return COSMS_CORE_FILE_FAILED_TO_ALLOCATE; } unsigned long long remaining_bytes = file_size; while (remaining_bytes != 0) { - DWORD bytes_to_read, read_bytes; + DWORD current_bytes_to_read, read_bytes; if (remaining_bytes > UINT_MAX) { - bytes_to_read = UINT_MAX; + current_bytes_to_read = UINT_MAX; } else { - bytes_to_read = (DWORD)remaining_bytes; + current_bytes_to_read = (DWORD)remaining_bytes; } - if (!ReadFile(file, (*content) + (file_size - remaining_bytes), bytes_to_read, &read_bytes, NULL)) { - free(*content); - CloseHandle(file); + if (ReadFile(file->native_file, (*buffer) + (file_size - remaining_bytes), current_bytes_to_read, &read_bytes, NULL) == 0) { + free(*buffer); return COSMS_CORE_FILE_FAILED_TO_READ; } remaining_bytes -= read_bytes; } - (*content)[file_size] = '\0'; - CloseHandle(file); + (*buffer)[file_size] = '\0'; #endif - + return COSMS_CORE_FILE_OK; } -CosmsCoreFileError cosms_core_file_write(const char *path, const char *content, unsigned long long size, int mode) { +CosmsCoreFileError cosms_core_file_write(struct cosms_core_file *file, char *buffer, unsigned int bytes_to_write, unsigned int *bytes_written) { + if ((file->mode & COSMS_CORE_FILE_MODE_WRITE) == 0) { + return COSMS_CORE_FILE_INVALID_OPERATION; + } + #if defined(__GNUC__) - int flags = O_WRONLY | O_CREAT; - if (mode & COSMS_CORE_FILE_MODE_APPEND) { - file |= O_APPEND; - } else if (mode) { - file |= O_TRUNC; + int written_bytes = write(file->native_file, buffer, bytes_to_write); + if (written_bytes == -1) { + return COSMS_CORE_FILE_FAILED_TO_WRITE; } - if (size > COSMS_CORE_FILE_LARGE) { - flags |= O_LARGEFILE; + if (bytes_written != NULL) { + (*bytes_written) = written_bytes; } - - int file = open(path, flags, 0644); - 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; - } - } - - unsigned long long remaining_bytes = size; - while (remaining_bytes != 0) { - unsigned int bytes_to_write; - if (remaining_bytes > UINT_MAX) { - bytes_to_write = UINT_MAX; - } else { - bytes_to_write = (unsigned int)remaining_bytes; - } - - int written_bytes = write(file, content + (size - remaining_bytes), bytes_to_write); - if (written_bytes == -1) { - close(file); - return COSMS_CORE_FILE_FAILED_TO_WRITE; - } - - remaining_bytes -= written_bytes; - } - - close(file); #elif defined(_WIN32) - HANDLE file; - if (mode & COSMS_CORE_FILE_MODE_APPEND) { - file = CreateFile(path, FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - } else { - file = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (WriteFile(file->native_file, buffer, bytes_to_write, (LPDWORD)bytes_written, NULL) == 0) { + return COSMS_CORE_FILE_FAILED_TO_WRITE; + } + #endif + + return COSMS_CORE_FILE_OK; +} + +CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char *buffer, unsigned long long bytes_to_write) { + if ((file->mode & COSMS_CORE_FILE_MODE_WRITE) == 0) { + return COSMS_CORE_FILE_INVALID_OPERATION; } - if (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; - } - } - - unsigned long long remaining_bytes = size; + #if defined(__GNUC__) + unsigned long long remaining_bytes = bytes_to_write; while (remaining_bytes != 0) { - DWORD bytes_to_write, written_bytes; + unsigned int current_bytes_to_write; if (remaining_bytes > UINT_MAX) { - bytes_to_write = UINT_MAX; + current_bytes_to_write = UINT_MAX; } else { - bytes_to_write = (DWORD)remaining_bytes; + current_bytes_to_write = (unsigned int)remaining_bytes; } - if (!WriteFile(file, content + (size - remaining_bytes), bytes_to_write, &written_bytes, NULL)) { - CloseHandle(file); + int written_bytes = write(file, content + (bytes_to_write - remaining_bytes), current_bytes_to_write); + if (written_bytes == -1) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } remaining_bytes -= written_bytes; } + #elif defined(_WIN32) + unsigned long long remaining_bytes = bytes_to_write; + while (remaining_bytes != 0) { + DWORD current_bytes_to_write, written_bytes; + if (remaining_bytes > UINT_MAX) { + current_bytes_to_write = UINT_MAX; + } else { + current_bytes_to_write = (DWORD)remaining_bytes; + } - CloseHandle(file); + if (WriteFile(file, buffer + (bytes_to_write - remaining_bytes), current_bytes_to_write, &written_bytes, NULL) == 0) { + return COSMS_CORE_FILE_FAILED_TO_WRITE; + } + + remaining_bytes -= written_bytes; + } #endif - + return COSMS_CORE_FILE_OK; } @@ -464,6 +408,9 @@ const char *cosms_core_file_error_string(CosmsCoreFileError error) { case COSMS_CORE_FILE_INVALID_FILE: return "cosms-file invalid native file given"; + case COSMS_CORE_FILE_INVALID_OPERATION: + return "cosms-file invalid operation for current file"; + default: return NULL; } diff --git a/tests/main.c b/tests/main.c index 150ee87..db7db0f 100644 --- a/tests/main.c +++ b/tests/main.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) Tristan Franssen, . + * + * This software is licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License in the file LICENSE or at + * http://www.apache.org/licenses/LICENSE-2.0 + */ #include "unit/unit.h" int main(void) { diff --git a/tests/unit/file.c b/tests/unit/file.c index fc13064..8b8fadd 100644 --- a/tests/unit/file.c +++ b/tests/unit/file.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) Tristan Franssen, . + * + * This software is licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License in the file LICENSE or at + * http://www.apache.org/licenses/LICENSE-2.0 + */ #include "unit/file.h" #include @@ -210,210 +218,13 @@ COSMS_CORE_TEST_TEST(file_size, ) COSMS_CORE_TEST_TEST(file_read, - COSMS_CORE_TEST_SUB_TEST(reading small file, - unsigned long long file_size = 0; - char *file_buffer = NULL; - CosmsCoreFileError error = cosms_core_file_read("tests/data/small-file.txt", &file_buffer, &file_size); - if (error == COSMS_CORE_FILE_OK) { - const char *expected_result = "Hello, World!"; - if (file_size != strlen(expected_result) || strcmp(expected_result, file_buffer) != 0) { - cosms_core_test_sub_test_error = "result does not match expected result"; - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_buffer != NULL) { - free(file_buffer); - } - ) - COSMS_CORE_TEST_SUB_TEST(reading large file, - unsigned long long file_size = 0; - char *file_buffer = NULL; - CosmsCoreFileError error = cosms_core_file_read("tests/data/large-file.txt", &file_buffer, &file_size); - if (error == COSMS_CORE_FILE_OK) { - unsigned long long expected_size = 5242880000ULL; - char *expected_result = (char*)malloc((expected_size + 1) * sizeof(char)); - if (!expected_result) { - printf("[-] failed to allocate memory for test aborting file read tests...\n"); - free(file_buffer); - return; - } - - memset(expected_result, 'a', expected_size); - expected_result[expected_size] = '\0'; - - if (file_size != expected_size || strcmp(expected_result, file_buffer) != 0) { - cosms_core_test_sub_test_error = "result does not match expected result"; - } - - free(expected_result); - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_buffer != NULL) { - free(file_buffer); - } - ) - - COSMS_CORE_TEST_SUB_TEST(reading non existing file, - unsigned long long file_size = 0; - char *file_buffer = NULL; - CosmsCoreFileError error = cosms_core_file_read("non-existing-file.cosms", &file_buffer, &file_size); - if (error != COSMS_CORE_FILE_NOT_FOUND) { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_buffer != NULL) { - free(file_buffer); - } - ) ) COSMS_CORE_TEST_TEST(file_write, - COSMS_CORE_TEST_SUB_TEST(writting small file, - char *file_buffer = "Hello, World!"; - CosmsCoreFileError error = cosms_core_file_write("tests/data/small-write-file.txt", file_buffer, strlen(file_buffer), COSMS_CORE_FILE_MODE_WRITE); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/small-write-file.txt", &file_content, NULL); - if (error == COSMS_CORE_FILE_OK) { - if (strcmp(file_buffer, file_content) != 0) { - cosms_core_test_sub_test_error = "file content not what was written"; - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) - - COSMS_CORE_TEST_SUB_TEST(writting big file, - unsigned long long large_file_size = 5242880000ULL; - char *large_file_buffer = (char*)malloc((large_file_size + 1) * sizeof(char)); - if (!large_file_buffer) { - printf("[-] failed to allocate memory for test aborting file read tests...\n"); - free(large_file_buffer); - return; - } - - memset(large_file_buffer, 'a', large_file_size); - large_file_buffer[large_file_size] = '\0'; - - CosmsCoreFileError error = cosms_core_file_write("tests/data/large-write-file.txt", large_file_buffer, large_file_size, COSMS_CORE_FILE_MODE_WRITE); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/large-write-file.txt", &file_content, NULL); - if (error == COSMS_CORE_FILE_OK) { - if (strcmp(large_file_buffer, file_content) != 0) { - cosms_core_test_sub_test_error = "file content not what was written"; - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - free(large_file_buffer); - ) - - COSMS_CORE_TEST_SUB_TEST(appending file, - char *file_buffer = "Hello, World!"; - CosmsCoreFileError error = cosms_core_file_write("tests/data/small-write-file.txt", file_buffer, strlen(file_buffer), COSMS_CORE_FILE_MODE_APPEND); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/small-write-file.txt", &file_content, NULL); - if (error == COSMS_CORE_FILE_OK) { - const char *expected_result = "Hello, World!Hello, World!"; - if (strcmp(expected_result, file_content) != 0) { - cosms_core_test_sub_test_error = "file content not what was written"; - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) - - COSMS_CORE_TEST_SUB_TEST(appending to non existing file, - char *file_buffer = "Hello, World!"; - CosmsCoreFileError error = cosms_core_file_write("tests/data/append-write-file.txt", file_buffer, strlen(file_buffer), COSMS_CORE_FILE_MODE_APPEND); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/append-write-file.txt", &file_content, NULL); - if (error == COSMS_CORE_FILE_OK) { - if (strcmp(file_buffer, file_content) != 0) { - cosms_core_test_sub_test_error = "file content not what was written"; - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) + ) COSMS_CORE_TEST_TEST(file_delete, - COSMS_CORE_TEST_SUB_TEST(deleting small file, - CosmsCoreFileError error = cosms_core_file_delete("tests/data/small-write-file.txt"); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/small-write-file.txt", &file_content, NULL); - if (error != COSMS_CORE_FILE_NOT_FOUND) { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) - - COSMS_CORE_TEST_SUB_TEST(deleting large file, - CosmsCoreFileError error = cosms_core_file_delete("tests/data/append-write-file.txt"); - if (error == COSMS_CORE_FILE_OK) { - char *file_content = NULL; - error = cosms_core_file_read("tests/data/append-write-file.txt", &file_content, NULL); - if (error != COSMS_CORE_FILE_NOT_FOUND) { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - - if (file_content != NULL) { - free(file_content); - } - } else { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) - - COSMS_CORE_TEST_SUB_TEST(deleting non existing file, - CosmsCoreFileError error = cosms_core_file_delete("non-existing-file.cosms"); - if (error != COSMS_CORE_FILE_NOT_FOUND) { - cosms_core_test_sub_test_error = cosms_core_file_error_string(error); - } - ) + ) diff --git a/tests/unit/file.h b/tests/unit/file.h index 58946da..d33929d 100644 --- a/tests/unit/file.h +++ b/tests/unit/file.h @@ -1,3 +1,11 @@ +/* + * Copyright (C) Tristan Franssen, . + * + * This software is licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License in the file LICENSE or at + * http://www.apache.org/licenses/LICENSE-2.0 + */ #ifndef COSMS_CORE_FILE_TEST #define COSMS_CORE_FILE_TEST diff --git a/tests/unit/unit.h b/tests/unit/unit.h index 6079d59..fbd3a3e 100644 --- a/tests/unit/unit.h +++ b/tests/unit/unit.h @@ -1,3 +1,11 @@ +/* + * Copyright (C) Tristan Franssen, . + * + * This software is licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License in the file LICENSE or at + * http://www.apache.org/licenses/LICENSE-2.0 + */ #ifndef COSMS_UNIT #define COSMS_UNIT