diff --git a/src/file.c b/src/file.c index 4cf538f..ff5b8fc 100644 --- a/src/file.c +++ b/src/file.c @@ -31,13 +31,16 @@ CosmsCoreFileError cosms_core_file_open(struct cosms_core_file *file, const char } 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; + flags |= O_WRONLY; + } + + if (mode & COSMS_CORE_FILE_MODE_APPEND) { + flags |= O_APPEND; + } else { + flags |= O_TRUNC; + if (mode & COSMS_CORE_FILE_MODE_CREATE) { + flags |= O_CREAT; + } } struct stat file_stat; @@ -79,11 +82,8 @@ CosmsCoreFileError cosms_core_file_open(struct cosms_core_file *file, const char } if (mode & COSMS_CORE_FILE_MODE_APPEND) { - access_flags |= GENERIC_WRITE; create_flag = OPEN_ALWAYS; - } - - if (mode & COSMS_CORE_FILE_MODE_CREATE) { + } else if (mode & COSMS_CORE_FILE_MODE_CREATE) { create_flag = CREATE_ALWAYS; } @@ -282,6 +282,10 @@ CosmsCoreFileError cosms_core_file_write(struct cosms_core_file *file, char *buf (*bytes_written) = written_bytes; } #elif defined(_WIN32) + if (file->mode & COSMS_CORE_FILE_MODE_APPEND) { + SetFilePointer(file->native_file, 0, NULL, FILE_END); + } + if (WriteFile(file->native_file, buffer, bytes_to_write, (LPDWORD)bytes_written, NULL) == 0) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } @@ -305,7 +309,7 @@ CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char current_bytes_to_write = (unsigned int)remaining_bytes; } - int written_bytes = write(file, content + (bytes_to_write - remaining_bytes), current_bytes_to_write); + int written_bytes = write(file->native_file, content + (bytes_to_write - remaining_bytes), current_bytes_to_write); if (written_bytes == -1) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } @@ -313,6 +317,13 @@ CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char remaining_bytes -= written_bytes; } #elif defined(_WIN32) + if (file->mode & COSMS_CORE_FILE_MODE_APPEND) { + LARGE_INTEGER zero; + zero.QuadPart = 0; + + SetFilePointerEx(file->native_file, zero, NULL, FILE_END); + } + unsigned long long remaining_bytes = bytes_to_write; while (remaining_bytes != 0) { DWORD current_bytes_to_write, written_bytes; @@ -322,7 +333,7 @@ CosmsCoreFileError cosms_core_file_write_all(struct cosms_core_file *file, char current_bytes_to_write = (DWORD)remaining_bytes; } - if (WriteFile(file, buffer + (bytes_to_write - remaining_bytes), current_bytes_to_write, &written_bytes, NULL) == 0) { + if (WriteFile(file->native_file, buffer + (bytes_to_write - remaining_bytes), current_bytes_to_write, &written_bytes, NULL) == 0) { return COSMS_CORE_FILE_FAILED_TO_WRITE; } diff --git a/tests/data/large-write-file.txt b/tests/data/large-write-file.txt new file mode 100644 index 0000000..888ba35 Binary files /dev/null and b/tests/data/large-write-file.txt differ diff --git a/tests/data/small-write-file.txt b/tests/data/small-write-file.txt new file mode 100644 index 0000000..2dd9088 --- /dev/null +++ b/tests/data/small-write-file.txt @@ -0,0 +1 @@ +Hello, World!Hello, World! \ No newline at end of file diff --git a/tests/test.h b/tests/test.h index d740e10..095cfdd 100644 --- a/tests/test.h +++ b/tests/test.h @@ -29,7 +29,7 @@ if (result == NULL) { \ printf("\r[PASS] test %s completed successfully!\n", current_test.name); \ } else { \ - printf("\r[FAIL] test %s failed with error: %s\n", current_test.name, result); \ + printf("\r[FAIL] test %s failed with error:\n\t%s\n", current_test.name, result); \ } \ \ test_index += 1; \ diff --git a/tests/unit/file.c b/tests/unit/file.c index 9a1b1b1..b2bd68d 100644 --- a/tests/unit/file.c +++ b/tests/unit/file.c @@ -10,6 +10,7 @@ #include +#include #include COSMS_CORE_TEST_TEST(file_open_small_file_read, @@ -189,10 +190,12 @@ COSMS_CORE_TEST_TEST(file_size_small_file, unsigned long long size = 0; error = cosms_core_file_get_size(&file, &size); if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); return cosms_core_file_error_string(error); } if (size != 13) { + cosms_core_file_close(&file); return "result does not match expected result"; } @@ -214,10 +217,12 @@ COSMS_CORE_TEST_TEST(file_size_large, unsigned long long size = 0; error = cosms_core_file_get_size(&file, &size); if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); return cosms_core_file_error_string(error); } if (size != 5242880000ULL) { + cosms_core_file_close(&file); return "result does not match expected result"; } @@ -255,10 +260,12 @@ COSMS_CORE_TEST_TEST(file_read_small_file, char buffer[14]; error = cosms_core_file_read(&file, buffer, bytes_to_read, &bytes_read); if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); return cosms_core_file_error_string(error); } if (bytes_to_read != bytes_read || strcmp(buffer, "Hello, World!") != 0) { + cosms_core_file_close(&file); return "result does not match expected result"; } @@ -283,17 +290,15 @@ COSMS_CORE_TEST_TEST(file_read_large_file, char *buffer = NULL; error = cosms_core_file_read_all(&file, &buffer, &bytes_read); if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); return cosms_core_file_error_string(error); } char *expected_result = (char*)malloc((bytes_to_read + 1) * sizeof(char)); if (expected_result == NULL) { + cosms_core_file_close(&file); free(buffer); - error = cosms_core_file_close(&file); - if (error != COSMS_CORE_FILE_OK) { - return cosms_core_file_error_string(error); - } return "Failed to allocate memory"; } @@ -303,6 +308,8 @@ COSMS_CORE_TEST_TEST(file_read_large_file, expected_result[bytes_to_read] = '\0'; if (bytes_to_read != bytes_read || strcmp(buffer, expected_result) != 0) { + cosms_core_file_close(&file); + free(expected_result); free(buffer); @@ -369,6 +376,7 @@ COSMS_CORE_TEST_TEST(file_read_file_using_wrong_mode, char buffer[14]; error = cosms_core_file_read(&file, buffer, bytes_to_read, &bytes_read); if (error != COSMS_CORE_FILE_INVALID_OPERATION) { + cosms_core_file_close(&file); return cosms_core_file_error_string(error); } @@ -391,6 +399,7 @@ COSMS_CORE_TEST_TEST(file_read_full_file_using_wrong_mode, char *buffer = NULL; error = cosms_core_file_read_all(&file, &buffer, &bytes_read); if (error != COSMS_CORE_FILE_INVALID_OPERATION) { + cosms_core_file_close(&file); if (error == COSMS_CORE_FILE_OK) { free(buffer); } @@ -406,7 +415,291 @@ COSMS_CORE_TEST_TEST(file_read_full_file_using_wrong_mode, return NULL; ) -COSMS_CORE_TEST_TEST(file_write, +COSMS_CORE_TEST_TEST(file_write_small_file, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/small-write-file.txt", COSMS_CORE_FILE_MODE_WRITE | COSMS_CORE_FILE_MODE_CREATE); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned int bytes_to_write = 13; + unsigned int bytes_written = 0; + + char *write_buffer = "Hello, World!"; + error = cosms_core_file_write(&file, write_buffer, bytes_to_write, &bytes_written); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + if (bytes_to_write != bytes_written) { + cosms_core_file_close(&file); + return "did not write all bytes to file"; + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_open(&file, "tests/data/small-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + char read_buffer[14] = { 0 }; + error = cosms_core_file_read(&file, read_buffer, bytes_to_write, NULL); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + if (strcmp(read_buffer, write_buffer) != 0) { + cosms_core_file_close(&file); + return "result does not match expected result"; + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + return NULL; +) + +COSMS_CORE_TEST_TEST(file_write_large_file, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/large-write-file.txt", COSMS_CORE_FILE_MODE_WRITE | COSMS_CORE_FILE_MODE_CREATE); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned long long bytes_to_write = 5242880000ULL; + char *write_buffer = (char*)malloc((bytes_to_write + 1) * sizeof(char)); + for (unsigned long long index = 0; index < bytes_to_write; index += 1) { + write_buffer[index] = 'a'; + } + + write_buffer[bytes_to_write] = '\0'; + error = cosms_core_file_write_all(&file, write_buffer, bytes_to_write); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + free(write_buffer); + + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + free(write_buffer); + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_open(&file, "tests/data/large-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + free(write_buffer); + return cosms_core_file_error_string(error); + } + + char *read_buffer = NULL; + error = cosms_core_file_read_all(&file, &read_buffer, NULL); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + free(write_buffer); + + return cosms_core_file_error_string(error); + } + + if (strcmp(read_buffer, write_buffer) != 0) { + cosms_core_file_close(&file); + + free(read_buffer); + free(write_buffer); + + return "result does not match expected result"; + } + + free(read_buffer); + free(write_buffer); + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + return NULL; +) + +COSMS_CORE_TEST_TEST(file_write_append_small_file, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/small-write-file.txt", COSMS_CORE_FILE_MODE_WRITE | COSMS_CORE_FILE_MODE_APPEND); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned int bytes_to_write = 13; + unsigned int bytes_written = 0; + + char *write_buffer = "Hello, World!"; + error = cosms_core_file_write(&file, write_buffer, bytes_to_write, &bytes_written); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + if (bytes_to_write != bytes_written) { + cosms_core_file_close(&file); + return "did not write all bytes to file"; + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_open(&file, "tests/data/small-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned int bytes_to_read = 26; + char read_buffer[27] = { 0 }; + error = cosms_core_file_read(&file, read_buffer, bytes_to_read, NULL); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + if (strcmp(read_buffer, "Hello, World!Hello, World!") != 0) { + cosms_core_file_close(&file); + return "result does not match expected result"; + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + return NULL; +) + +COSMS_CORE_TEST_TEST(file_write_append_large_file, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/large-write-file.txt", COSMS_CORE_FILE_MODE_WRITE | COSMS_CORE_FILE_MODE_APPEND); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned long long bytes_to_write = 2; + char *write_buffer = "bb"; + error = cosms_core_file_write_all(&file, write_buffer, bytes_to_write); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_open(&file, "tests/data/large-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned long long bytes_to_read = 5242880002ULL; + unsigned long long bytes_read = 0; + char *read_buffer = NULL; + error = cosms_core_file_read_all(&file, &read_buffer, &bytes_read); + if (error != COSMS_CORE_FILE_OK) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + char *expected_result = (char*)malloc((bytes_to_read + 1) * sizeof(char)); + for (unsigned long long index = 0; index < bytes_to_read; index += 1) { + expected_result[index] = 'a'; + } + + expected_result[bytes_to_read - 2] = 'b'; + expected_result[bytes_to_read - 1] = 'b'; + expected_result[bytes_to_read] = '\0'; + + if (strcmp(read_buffer, expected_result) != 0) { + cosms_core_file_close(&file); + + free(expected_result); + free(read_buffer); + + return "result does not match expected result"; + } + + free(expected_result); + free(read_buffer); + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + return NULL; +) + +COSMS_CORE_TEST_TEST(file_write_using_wrong_mode, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/small-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned int bytes_to_write = 13; + unsigned int bytes_written = 0; + + char *write_buffer = "Hello, World!"; + error = cosms_core_file_write(&file, write_buffer, bytes_to_write, &bytes_written); + if (error != COSMS_CORE_FILE_INVALID_OPERATION) { + cosms_core_file_close(&file); + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + free(write_buffer); + return cosms_core_file_error_string(error); + } + + return NULL; +) + +COSMS_CORE_TEST_TEST(file_write_full_file_using_wrong_mode, + struct cosms_core_file file; + CosmsCoreFileError error = cosms_core_file_open(&file, "tests/data/large-write-file.txt", COSMS_CORE_FILE_MODE_READ); + if (error != COSMS_CORE_FILE_OK) { + return cosms_core_file_error_string(error); + } + + unsigned long long bytes_to_write = 5242880000ULL; + char *write_buffer = (char*)malloc((bytes_to_write + 1) * sizeof(char)); + for (unsigned long long index = 0; index < bytes_to_write; index += 1) { + write_buffer[index] = 'a'; + } + + write_buffer[bytes_to_write] = '\0'; + error = cosms_core_file_write_all(&file, write_buffer, bytes_to_write); + if (error != COSMS_CORE_FILE_INVALID_OPERATION) { + cosms_core_file_close(&file); + free(write_buffer); + + return cosms_core_file_error_string(error); + } + + error = cosms_core_file_close(&file); + if (error != COSMS_CORE_FILE_OK) { + free(write_buffer); + return cosms_core_file_error_string(error); + } + return NULL; ) diff --git a/tests/unit/file.h b/tests/unit/file.h index 9c662a7..adbe567 100644 --- a/tests/unit/file.h +++ b/tests/unit/file.h @@ -35,7 +35,13 @@ COSMS_CORE_TEST_DEFINE(file_read_full_non_existing_file); COSMS_CORE_TEST_DEFINE(file_read_file_using_wrong_mode); COSMS_CORE_TEST_DEFINE(file_read_full_file_using_wrong_mode); -COSMS_CORE_TEST_DEFINE(file_write); +COSMS_CORE_TEST_DEFINE(file_write_small_file); +COSMS_CORE_TEST_DEFINE(file_write_large_file); +COSMS_CORE_TEST_DEFINE(file_write_append_small_file); +COSMS_CORE_TEST_DEFINE(file_write_append_large_file); +COSMS_CORE_TEST_DEFINE(file_write_using_wrong_mode); +COSMS_CORE_TEST_DEFINE(file_write_full_file_using_wrong_mode); + COSMS_CORE_TEST_DEFINE(file_delete); COSMS_CORE_TEST_EXPORT(file, @@ -63,7 +69,13 @@ COSMS_CORE_TEST_EXPORT(file, COSMS_CORE_TEST_EXPORT_TEST(file_read_file_using_wrong_mode), COSMS_CORE_TEST_EXPORT_TEST(file_read_full_file_using_wrong_mode), - COSMS_CORE_TEST_EXPORT_TEST(file_write), + COSMS_CORE_TEST_EXPORT_TEST(file_write_small_file), + COSMS_CORE_TEST_EXPORT_TEST(file_write_large_file), + COSMS_CORE_TEST_EXPORT_TEST(file_write_append_small_file), + COSMS_CORE_TEST_EXPORT_TEST(file_write_append_large_file), + COSMS_CORE_TEST_EXPORT_TEST(file_write_using_wrong_mode), + COSMS_CORE_TEST_EXPORT_TEST(file_write_full_file_using_wrong_mode), + COSMS_CORE_TEST_EXPORT_TEST(file_delete) );