diff --git a/include/common.h b/include/common.h index 9660199..987794e 100644 --- a/include/common.h +++ b/include/common.h @@ -30,19 +30,24 @@ enum configurations { fflush(stdout); \ fprintf(stream, __VA_ARGS__); \ } while (0) + #define PERROR_MACRO(s) do { \ int errnum = errno; \ char* err_msg = strerror(errnum); /* XXX: Thread race possible */ \ fflush(stdout); \ fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, (s), err_msg); \ } while (0) -#define FATAL_ERROR_PRINT(...) \ + +#define FATAL_ERROR_PRINT(...) do { \ FPRINTF_MACRO(stderr, __VA_ARGS__); \ - putc('\n', stderr) + putc('\n', stderr); \ +} while (0) + #define FATAL_ERROR(...) do { \ FATAL_ERROR_PRINT(__VA_ARGS__); \ exit(EXIT_FAILURE); \ } while (0) + #define FATAL_ERROR_RET(...) do { \ FATAL_ERROR_PRINT(__VA_ARGS__); \ return EXIT_FAILURE; \ @@ -83,10 +88,9 @@ typedef off_t file_offset_t; #define INT2STR(x) STRINGIZE(x) #define YES_NO(x) ((x) ? STR_YN_YES : STR_YN_NO) #define READ_CONFIG(x) (config & (x)) -#define SET_CONFIG(x) \ - config |= (x) -#define CLEAR_CONFIG(x) \ - config &= ~(x) +#define SET_CONFIG(x) config |= (x) +#define CLEAR_CONFIG(x) config &= ~(x) + #define LOOP_ACTION_CONFIG(f, x) \ f(x); \ continue diff --git a/include/file_boundaries.h b/include/file_boundaries.h index bba61dc..4df1926 100644 --- a/include/file_boundaries.h +++ b/include/file_boundaries.h @@ -1,9 +1,9 @@ #ifndef _FILE_BOUNDARIES_H #define _FILE_BOUNDARIES_H -#include -#include #include +#include +#include #include #include "common.h" diff --git a/src/MTPRNG.c b/src/MTPRNG.c index 06cdf99..d83ceac 100644 --- a/src/MTPRNG.c +++ b/src/MTPRNG.c @@ -31,24 +31,28 @@ void mt_seed(uint32_t* seed_ptr) { : *seed_ptr; uint32_t x = seed; - for (mti = 0; mti < N; mti++) { + + for (mti = 0; mti < N; mti++) mt[mti] = (x = (UINT32_C(1812433253) * (x ^ (x >> 30)) + mti)); - } } uint32_t mt_next(void) { uint32_t y; + if (mti >= N) { size_t kk; + for (kk = 0; kk < N_sub_M; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); mt[kk] = mt[kk + (size_t) M] ^ (y >> 1) ^ ((y & 1) * MATRIX_A); } + for (; kk < N_sub_1; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); mt[kk] = mt[kk + M_sub_N] ^ (y >> 1) ^ ((y & 1) * MATRIX_A); } + y = (mt[N_sub_1] & UPPER_MASK) | (mt[0] & LOWER_MASK); mt[N_sub_1] = mt[M_sub_1] ^ (y >> 1) ^ ((y & 1) * MATRIX_A); mti = 0; diff --git a/src/atoumax_base10.c b/src/atoumax_base10.c index 1cb5735..71529e8 100644 --- a/src/atoumax_base10.c +++ b/src/atoumax_base10.c @@ -3,6 +3,7 @@ /* function implementations */ uintmax_t atoumax_base10(const char* s) { uintmax_t result = 0; + for (const char* p = s; *p != '\0'; ++p) { char c = *p; @@ -13,10 +14,12 @@ uintmax_t atoumax_base10(const char* s) { } uintmax_t digit = c - '0'; - if ((uintmax_t) (result + digit) < result) { + + if ((uintmax_t) (result + digit) < result) FATAL_ERROR("Integer overflow (passed string = '%s')", s); - } + result = (result * 10) + digit; } + return result; } diff --git a/src/corrupter.c b/src/corrupter.c index 2d16445..da146a4 100644 --- a/src/corrupter.c +++ b/src/corrupter.c @@ -34,11 +34,12 @@ static bool get_chance(uint16_t desired_chance) { uint16_t cdf[UINT16_MAX_PLUS_1]; memset(cdf, 0, sizeof(cdf)); - for (uint16_t i = 0; i < UINT16_MAX; i++) { + + for (uint16_t i = 0; i < UINT16_MAX; i++) cdf[i] = (i <= desired_chance) ? i + 1 : cdf[i - 1]; - } uint16_t random_number = mt_next() & UINT16_MAX; + return random_number < cdf[desired_chance]; } @@ -48,6 +49,7 @@ static bool is_line_ending(byte c) { Corrupter_Result* corrupt_file(Corrupter_Param* param) { Corrupter_Result* result = malloc(sizeof(Corrupter_Result)); + if (result == NULL) return NULL; @@ -111,6 +113,7 @@ Corrupter_Result* corrupt_file(Corrupter_Param* param) { for (file_offset_t i = start; i < end; i++) { FSEEK_MACRO(file, i, SEEK_SET); byte byte_value; + if (fread(&byte_value, sizeof(byte), 1, file) != 1) { result->error = true; fclose(file); @@ -125,6 +128,7 @@ Corrupter_Result* corrupt_file(Corrupter_Param* param) { // generate bit mask unsigned char damage_left = (unsigned char) param->threshold; static bool bit_mask[CHAR_BIT]; + for (unsigned char bit = 0; bit < CHAR_BIT; bit++) { if (get_chance(probability) && (damage_left > 0)) { bit_mask[bit] = true; @@ -135,6 +139,7 @@ Corrupter_Result* corrupt_file(Corrupter_Param* param) { } bool damaged_byte = false; + for (unsigned char bit = 0; bit < threshold; bit++) { if (bit_mask[bit] == false) continue; @@ -146,6 +151,7 @@ Corrupter_Result* corrupt_file(Corrupter_Param* param) { // write the modified byte back to the file FSEEK_MACRO(file, i, SEEK_SET); + if (fwrite(&byte_value, sizeof(byte), 1, file) == 1) continue; @@ -163,5 +169,6 @@ Corrupter_Result* corrupt_file(Corrupter_Param* param) { } result->error = false; + return result; } diff --git a/src/endianness_tools.c b/src/endianness_tools.c index 05bcf29..abaa6cb 100644 --- a/src/endianness_tools.c +++ b/src/endianness_tools.c @@ -2,7 +2,7 @@ #define ORDER_NATIVE_U32 0x01234567 #define ORDER_LITTLE_ENDIAN_S4 "\x67\x45\x23\x01" -#define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" +#define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" #define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value endianness_t detect_endianness(void) { @@ -11,6 +11,7 @@ endianness_t detect_endianness(void) { ifeq_b32_ret(as_bytes, ORDER_LITTLE_ENDIAN_S4, DETECTED_LITTLE_ENDIAN); ifeq_b32_ret(as_bytes, ORDER_BIG_ENDIAN_S4, DETECTED_BIG_ENDIAN ); + return UNSUPPORTED_ENDIANNESS; } @@ -18,7 +19,9 @@ void reorder_b32(uint32_t* ptr) { if (ptr == NULL) return; - uint32_t result = ((*ptr >> 24) & 0xFF) | ((*ptr >> 8) & 0xFF00) | - ((*ptr << 8) & 0xFF0000) | ((*ptr << 24) & 0xFF000000); + uint32_t result = + ((*ptr >> 24) & 0x000000FF) | ((*ptr >> 8) & 0x0000FF00) | + ((*ptr << 8) & 0x00FF0000) | ((*ptr << 24) & 0xFF000000); + *ptr = result; } diff --git a/src/ends_with.c b/src/ends_with.c index 71f99b4..d1db486 100644 --- a/src/ends_with.c +++ b/src/ends_with.c @@ -16,10 +16,14 @@ bool ends_with_casefold(const char* str, const char* substr) { if (str_len < substr_len) return false; - for (const char* p = str + str_len - substr_len, * q = substr; - *p != '\0' && *q != '\0'; p++, q++) { + for ( + const char* p = str + str_len - substr_len, * q = substr; + *p != '\0' && *q != '\0'; + p++, q++ + ) { if (tolower(*p) != tolower(*q)) return false; } + return true; } diff --git a/src/file_boundaries.c b/src/file_boundaries.c index 542a493..f8133b3 100644 --- a/src/file_boundaries.c +++ b/src/file_boundaries.c @@ -1,11 +1,11 @@ #include "file_boundaries.h" /* macros: definitions */ -#define WAV_CHUNK_ID "RIFF" +#define WAV_CHUNK_ID "RIFF" #define WAV_SUBCHUNK_DATA_ID "data" /* macros: lambdas */ -#define DETERMINE_BOUNDARIES_FREAD_ERROR_HANDLING \ +#define DETERMINE_BOUNDARIES_FREAD_ERROR_HANDLING do { \ if (feof(file)) { \ boundaries->invalid_file = true; \ return boundaries; \ @@ -13,18 +13,22 @@ \ PERROR_MACRO("fread"); \ exit(EXIT_FAILURE); \ - return NULL + \ + return NULL; \ +} while (0) /* function implementations */ file_boundaries_t* determine_boundaries_BMP(FILE* file) { rewind(file); FATAL_ERROR("Feature 'determine_boundaries_BMP' not available. Coming " "soon!"); + return false; } file_boundaries_t* determine_boundaries_WAV(FILE* file) { file_boundaries_t* boundaries = malloc(sizeof(file_boundaries_t)); + if (boundaries == NULL) { PERROR_MACRO("fatal: malloc @ determine_boundaries_WAV"); exit(EXIT_FAILURE); @@ -33,6 +37,7 @@ file_boundaries_t* determine_boundaries_WAV(FILE* file) { // prepare endianness_t endianness = detect_endianness(); + if (endianness == UNSUPPORTED_ENDIANNESS) { FATAL_ERROR("Unsupported endianness of the machine"); return NULL; @@ -45,9 +50,8 @@ file_boundaries_t* determine_boundaries_WAV(FILE* file) { char chunk_id[4]; uint32_t chunk_size; - if (fread(chunk_id, sizeof(char), 4, file) != 4) { + if (fread(chunk_id, sizeof(char), 4, file) != 4) DETERMINE_BOUNDARIES_FREAD_ERROR_HANDLING; - } if (strncmp(chunk_id, WAV_CHUNK_ID, 4)) { boundaries->invalid_file = true; @@ -55,17 +59,15 @@ file_boundaries_t* determine_boundaries_WAV(FILE* file) { } // Read the next 4 bytes (chunk size) and skip the rest of the RIFF chunk - if (fread(&chunk_size, sizeof(uint32_t), 1, file) != 1) { + if (fread(&chunk_size, sizeof(uint32_t), 1, file) != 1) DETERMINE_BOUNDARIES_FREAD_ERROR_HANDLING; - } FSEEK_MACRO(file, (file_offset_t) chunk_size - FILE_OFFSET_C(4), SEEK_CUR); - while (true) { + for (;;) { if (fread(chunk_id, 1, 4, file) != 4 || - fread(&chunk_size, sizeof(uint32_t), 1, file) != 1) { + fread(&chunk_size, sizeof(uint32_t), 1, file) != 1) DETERMINE_BOUNDARIES_FREAD_ERROR_HANDLING; - } if (need_to_reorder_values) reorder_b32(&chunk_size); diff --git a/src/file_type.c b/src/file_type.c index e525ae1..360e2df 100644 --- a/src/file_type.c +++ b/src/file_type.c @@ -4,12 +4,14 @@ #define FILE_TYPE_CHECK_RET(ext, type) \ if (ends_with_casefold(file_name, ext) && is_valid_file(file, type)) \ return true -#define FILE_TYPE_FREAD_ERROR_HANDLING \ + +#define FILE_TYPE_FREAD_ERROR_HANDLING do { \ if (feof(file)) \ return false; \ \ PERROR_MACRO("fread"); \ - exit(EXIT_FAILURE) + exit(EXIT_FAILURE); \ +} while (0) /* function definitions */ static bool header_check(FILE* file, const char* id, size_t length); @@ -21,9 +23,8 @@ static bool header_check(FILE* file, const char* id, size_t length) { for (size_t i = 0; i < length; i++) { char c; - if (fread(&c, sizeof(char), 1, file) != 1) { + if (fread(&c, sizeof(char), 1, file) != 1) FILE_TYPE_FREAD_ERROR_HANDLING; - } if (c != id[i]) return false; diff --git a/src/main.c b/src/main.c index b61f960..71df4b5 100644 --- a/src/main.c +++ b/src/main.c @@ -51,7 +51,7 @@ uint32_t PRNG_seed_value; uint8_t config = C_CONFIRM; /* macros: procedures */ -#define DOES_NOT_EXIST \ +#define ERROR_DOES_NOT_EXIST \ if (errno == ENOENT) { \ FPRINTF_MACRO(stderr, "Error: File %s doesn't exist\n", file_path); \ return EXIT_FAILURE; \ @@ -77,13 +77,16 @@ bool args_match(const char* arg, const char* args_list[]); #ifdef SYS_NT static char* correct_slashes(const char* path) { char* new_path = strdup(path); + if (new_path == NULL) return NULL; char* ptr = new_path; + while (*ptr != '\0') { if (*ptr == '\\') *ptr = '/'; + ptr++; } @@ -99,10 +102,12 @@ static char* my_basename(const char* raw_path) { strdup #endif (raw_path); + if (path == NULL) return NULL; char* base = malloc(FILENAME_MAX * sizeof(char)); + if (base == NULL) { free(path); PERROR_MACRO("malloc"); @@ -113,6 +118,7 @@ static char* my_basename(const char* raw_path) { size_t fname_len = strlen(path); const char* last_slash = strrchr(path, '/'); + if (last_slash != NULL) fname_len = strlen(last_slash + 1); @@ -129,6 +135,7 @@ static void parse_value(uint8_t destination, const char* arg) { return; uintmax_t result = atoumax_base10(arg); + switch (destination) { case ARG_DEST_POSSIBILITY: if (result == 0 || result > UINT16_MAX) { @@ -163,6 +170,7 @@ static void parse_value(uint8_t destination, const char* arg) { default: FATAL_ERROR("Unknown argument destination (value = %" PRIu16 ")", destination); + return; } } @@ -223,9 +231,14 @@ int main(int argc, char** argv) { " -seed : Specify a 32-bit seed for the PRNG. If you want " "to keep it\n" " random, set the option to `random`.\n", - program_name, UINT16_MAX, probability, threshold, - (uintmax_t) SIZE_MAX, passes); + program_name, + UINT16_MAX, + probability, + threshold, + (uintmax_t) SIZE_MAX, + passes); free(program_name); + return EXIT_FAILURE; } @@ -280,27 +293,32 @@ int main(int argc, char** argv) { #ifdef SYS_UNIX_GENERAL // check if the file is a directory struct stat path_stat; + if (stat(file_path, &path_stat) != 0) { - if (errno == ENOENT) { - DOES_NOT_EXIST; - } + if (errno == ENOENT) + ERROR_DOES_NOT_EXIST; + PERROR_MACRO("stat"); + return EXIT_FAILURE; } if (S_ISDIR(path_stat.st_mode)) { FPRINTF_MACRO(stderr, "Error: %s is a directory\n", file_path); + return EXIT_FAILURE; } #endif // open the file FILE* file = fopen(file_path, "rb+"); + if (file == NULL) { #ifndef SYS_UNIX_GENERAL - DOES_NOT_EXIST; + ERROR_DOES_NOT_EXIST; #endif PERROR_MACRO("fopen"); + return EXIT_FAILURE; } @@ -320,11 +338,11 @@ int main(int argc, char** argv) { // print configuration: custom seed printf("> Custom seed: "); - if (READ_CONFIG(C_CUSTOM_SEED)) { + + if (READ_CONFIG(C_CUSTOM_SEED)) printf("%" PRIu32 "\n", PRNG_seed_value); - } else { + else puts(STR_YN_NO); - } // print configuration: file type printf("> File type: %s\n" @@ -340,6 +358,7 @@ int main(int argc, char** argv) { if (READ_CONFIG(C_CONFIRM)) { printf("Are you sure? (Y/n): "); fflush(stdout); + if ((getchar()) != (int) 'Y') { printf("File corruption aborted.\n"); return EXIT_FAILURE; @@ -364,12 +383,15 @@ int main(int argc, char** argv) { }; Corrupter_Result* result = corrupt_file(¶m); + if (result == NULL) { PERROR_MACRO("corrupt_file memory allocation"); + return EXIT_FAILURE; } else if (result->error) { free(result); PERROR_MACRO("corrupt_file"); + return EXIT_FAILURE; } @@ -379,11 +401,11 @@ int main(int argc, char** argv) { size_t dmg = result->damaged_bytes, fsize = result->file_size, passes = param.passes; printf("Byte hit counter: %" PRIuMAX " / %" PRIuMAX " = %.3Lf%%\n", - (uintmax_t) dmg, (uintmax_t) (fsize * passes), + (uintmax_t) dmg, + (uintmax_t) (fsize * passes), ((long double) dmg * 100.l) / (long double) (fsize * passes)); - } else { + } else puts("No bytes were damaged"); - } free(result); diff --git a/src/strdup.c b/src/strdup.c index 2c7ee5f..a5258d6 100644 --- a/src/strdup.c +++ b/src/strdup.c @@ -8,6 +8,7 @@ char* strdup(const char* s) { } char* copy = malloc((strlen(s) + 1) * sizeof(char)); + if (copy == NULL) return NULL;