From c607046831ead8e1dff77c13b23fc1c50cb7310c Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Fri, 4 Mar 2022 20:05:52 +0100 Subject: [PATCH] Implemented improved method for detecting identical files. --- frontend/src/crypt.c | 4 +- frontend/src/main.c | 33 +++++--------- frontend/src/pwgen.c | 22 ++-------- frontend/src/utils.c | 102 +++++++++++++++++++------------------------ frontend/src/utils.h | 5 +-- 5 files changed, 63 insertions(+), 103 deletions(-) diff --git a/frontend/src/crypt.c b/frontend/src/crypt.c index 6550a7f..3d89b78 100644 --- a/frontend/src/crypt.c +++ b/frontend/src/crypt.c @@ -67,7 +67,7 @@ int encrypt(const char *const passphrase, const CHR *const input_path, const CHR goto clean_up; } - const uint64_t file_size = get_file_size(file_in); + const uint64_t file_size = get_size(file_in); if (file_size == UINT64_MAX) { FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr); @@ -252,7 +252,7 @@ int decrypt(const char *const passphrase, const CHR *const input_path, const CHR goto clean_up; } - const uint64_t file_size = get_file_size(file_in); + const uint64_t file_size = get_size(file_in); if (file_size == UINT64_MAX) { FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr); diff --git a/frontend/src/main.c b/frontend/src/main.c index 96e99f5..f69371b 100644 --- a/frontend/src/main.c +++ b/frontend/src/main.c @@ -144,11 +144,12 @@ static void sigint_handler(const int sig) int MAIN(const int argc, CHR *const argv[]) { + int result = EXIT_FAILURE; + const CHR *input_file = NULL, *output_file = NULL; + char *passphrase_buffer = NULL; + init_terminal(); setup_signal_handler(SIGINT, sigint_handler); - int result = EXIT_FAILURE; - CHR *input_file = NULL, *output_file = NULL; - char *passphrase_buffer = NULL; FPRINTF(stderr, T("SlunkCrypt Utility (%") T(PRIstr) T("-%") T(PRIstr) T("), by LoRd_MuldeR \n"), OS_TYPE, CPU_ARCH); FPRINTF(stderr, T("Using libSlunkCrypt v%u.%u.%u [%") T(PRIstr) T("]\n\n"), SLUNKCRYPT_VERSION_MAJOR, SLUNKCRYPT_VERSION_MINOR, SLUNKCRYPT_VERSION_PATCH, SLUNKCRYPT_BUILD); @@ -219,23 +220,23 @@ int MAIN(const int argc, CHR *const argv[]) } } - input_file = absolute_path(argv[PW_FROM_ENV ? 2U : 3U]); - if ((!input_file) || (!input_file[0U])) + input_file = argv[PW_FROM_ENV ? 2U : 3U]; + if (!input_file[0U]) { - FPUTS(T("Error: Input file path could not be resolved!\n\n"), stderr); + FPUTS(T("Error: The specified input file name must not be empty!\n\n"), stderr); goto clean_up; } - output_file = absolute_path(argv[PW_FROM_ENV ? 3U : 4U]); - if ((!output_file) || (!output_file[0U])) + output_file = argv[PW_FROM_ENV ? 3U : 4U]; + if (!output_file[0U]) { - FPUTS(T("Error: Output file path could not be resolved!\n\n"), stderr); + FPUTS(T("Error: The specified output file name must not be empty!\n\n"), stderr); goto clean_up; } - if (!path_compare(input_file, output_file)) + if (same_file(input_file, output_file) > 0) { - FPUTS(T("Error: Input and output files must not be the same path! (effectively)\n\n"), stderr); + FPUTS(T("Error: The input and output files must not be the same!\n\n"), stderr); goto clean_up; } @@ -316,16 +317,6 @@ clean_up: free(passphrase_buffer); } - if (input_file) - { - free(input_file); - } - - if (output_file) - { - free(output_file); - } - return result; } diff --git a/frontend/src/pwgen.c b/frontend/src/pwgen.c index b5f77b2..90970b0 100644 --- a/frontend/src/pwgen.c +++ b/frontend/src/pwgen.c @@ -56,9 +56,8 @@ static void trim_end_of_line(char *const buffer) char *read_passphrase(const CHR *const file_name) { - char *buffer = NULL; - CHR *passphrase_path = NULL; FILE *passphrase_file = NULL; + char *buffer = NULL; if ((!file_name) || (!file_name[0U])) { @@ -66,20 +65,10 @@ char *read_passphrase(const CHR *const file_name) goto finish; } - if (STRICMP(file_name, T("-"))) - { - passphrase_path = absolute_path(file_name); - if ((!passphrase_path) || (!passphrase_path[0U])) - { - FPUTS(T("Error: Passphrase input file path could not be resolved!\n\n"), stderr); - goto finish; - } - } - - passphrase_file = passphrase_path ? FOPEN(passphrase_path, T("rb")): stdin; + passphrase_file = STRICMP(file_name, T("-")) ? FOPEN(file_name, T("rb")) : stdin; if (!passphrase_file) { - FPRINTF(stderr, T("Error: Failed to open passphrase file \"%") T(PRISTR) T("\" for reading!\n\n%") T(PRISTR) T("\n\n"), passphrase_path, STRERROR(errno)); + FPRINTF(stderr, T("Error: Failed to open passphrase file \"%") T(PRISTR) T("\" for reading!\n\n%") T(PRISTR) T("\n\n"), file_name, STRERROR(errno)); goto finish; } @@ -108,11 +97,6 @@ finish: fclose(passphrase_file); } - if (passphrase_path) - { - free(passphrase_path); - } - return buffer; } diff --git a/frontend/src/utils.c b/frontend/src/utils.c index deb945f..4c13e4b 100644 --- a/frontend/src/utils.c +++ b/frontend/src/utils.c @@ -27,6 +27,7 @@ # include # include # define STAT_T struct _stati64 +# define STAT(X,Y) _wstati64((X),(Y)) # define FSTAT(X,Y) _fstati64((X),(Y)) # define FILENO(X) _fileno((X)) # define S_IFMT _S_IFMT @@ -39,9 +40,11 @@ # include # if defined(__USE_LARGEFILE64) && (__USE_LARGEFILE64) # define STAT_T struct stat64 +# define STAT(X,Y) stat64((X),(Y)) # define FSTAT(X,Y) fstat64((X),(Y)) # else # define STAT_T struct stat +# define STAT(X,Y) stat((X),(Y)) # define FSTAT(X,Y) fstat((X),(Y)) # endif # define FILENO(X) fileno((X)) @@ -111,30 +114,6 @@ void setup_signal_handler(const int signo, signal_handler_t* const handler) // String functions // ========================================================================== -char *concat_str(const char *const str, ...) -{ - const char *ptr; - char *buffer; - size_t buff_size = 1U; - va_list arg; - va_start(arg, str); - for (ptr = str; ptr != NULL; ptr = va_arg(arg, const char*)) - { - buff_size += strlen(ptr); - } - if ((buffer = (char*)calloc(buff_size, sizeof(char)))) - { - va_end(arg); - va_start(arg, str); - for (ptr = str; ptr != NULL; ptr = va_arg(arg, const char*)) - { - strcat(buffer, ptr); - } - } - va_end(arg); - return buffer; -} - char* CHR_to_utf8(const CHR *const input) { #ifdef _WIN32 @@ -259,52 +238,59 @@ size_t fread_ui64(uint64_t *const value, FILE *const stream) // File functions // ========================================================================== -#define JOIN_PATHS(X,Y) concat_str((X), "/", (Y), NULL) - -CHR *absolute_path(const CHR *const path) +typedef struct { + uint64_t dev; + uint64_t ino; +} +file_uid_t; + +static int get_file_unique_id(const CHR *const path, file_uid_t *const file_id) +{ + int retval = -1; #ifdef _WIN32 - wchar_t *const result = _wfullpath(NULL, path, 0U); -#else - char *result = realpath(path, NULL); - if ((!result) && path[0U] && (path[0U] != '/')) + const HANDLE handle = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0U, NULL); + if (handle != INVALID_HANDLE_VALUE) { - char *const cwd = getcwd(NULL, 0U); - if (cwd) + BY_HANDLE_FILE_INFORMATION file_info; + if ((retval = (!GetFileInformationByHandle(handle, &file_info))) == 0) { - const char *path_off = path; - while ((path_off[0U] == '.') && (path_off[1U] == '/')) - { - path_off += 2U; - while (path_off[0U] == '/') ++path_off; - } - result = JOIN_PATHS(cwd, path_off); - free(cwd); + file_id->dev = file_info.dwVolumeSerialNumber; + file_id->ino = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; } + CloseHandle(handle); + } +#else + STAT_T file_info; + if ((retval = STAT(path, &file_info)) == 0) + { + file_id->dev = file_info.st_dev; + file_id->ino = file_info.st_ino; } #endif - return result ? result : STRDUP(path); + return retval; } -int path_compare(const CHR *const path0, const CHR *const path1) +int same_file(const CHR *const path0, const CHR *const path1) { -#ifdef _WIN32 - return _wcsicmp(path0, path1); -#else - return strcmp(path0, path1); -#endif -} - -uint64_t get_file_size(FILE* const file) -{ - STAT_T stat; - if (FSTAT(FILENO(file), &stat) == 0) + file_uid_t file_id0, file_id1; + if ((get_file_unique_id(path0, &file_id0) == 0) && (get_file_unique_id(path1, &file_id1) == 0)) { - const uint16_t file_type = stat.st_mode & S_IFMT; - if ((file_type != S_IFDIR) && (file_type != S_IFIFO)) + return (file_id0.dev == file_id1.dev) && (file_id0.ino == file_id1.ino); + } + return -1; +} + +uint64_t get_size(FILE *const file) +{ + STAT_T file_info; + if (FSTAT(FILENO(file), &file_info) == 0) + { + const unsigned ftype = file_info.st_mode & S_IFMT; + if ((ftype != S_IFDIR) && (ftype != S_IFIFO)) { - const int64_t ssize = stat.st_size; - return (ssize >= 0) ? ((uint64_t)ssize) : 0U; + const int64_t size = file_info.st_size; + return (size >= 0) ? ((uint64_t)size) : 0U; } return 0U; } diff --git a/frontend/src/utils.h b/frontend/src/utils.h index a2a66f8..0282e85 100644 --- a/frontend/src/utils.h +++ b/frontend/src/utils.h @@ -24,10 +24,9 @@ size_t fread_ui64(uint64_t *const value, FILE *const stream); char* CHR_to_utf8(const CHR *const input); -CHR *absolute_path(const CHR *const path); -int path_compare(const CHR *const path0, const CHR *const path1); +int same_file(const CHR*const path0, const CHR*const path1); +uint64_t get_size(FILE *const file); const CHR *get_file_name(const CHR *path); -uint64_t get_file_size(FILE* const file); uint64_t round_down(const uint64_t value, const uint64_t base);