/** * Verify for all algorithms, that rhash_final() returns the same result as * rhash_print(). */ static void test_results_consistency(void) { const char * msg = "a"; size_t msg_size = strlen(msg); size_t digest_size; struct rhash_context *ctx; unsigned char res1[70]; char res2[70]; unsigned i, hash_id; for(i = 0, hash_id = 1; (hash_id & RHASH_ALL_HASHES); hash_id <<= 1, i++) { digest_size = rhash_get_digest_size(hash_id); assert(digest_size < 70); ctx = rhash_init(hash_id); #ifdef USE_BTIH_WITH_TEST_FILENAME if((hash_id & RHASH_BTIH) != 0) { unsigned long long total_size = msg_size; rhash_transmit(RMSG_BT_ADD_FILE, ctx, RHASH_STR2UPTR("test.txt"), (rhash_uptr_t)&total_size); } #endif rhash_update(ctx, msg, msg_size); rhash_final(ctx, res1); rhash_print(res2, ctx, hash_id, RHPR_RAW); rhash_free(ctx); if(memcmp(res1, res2, digest_size) != 0) { log_message("failed: inconsistent %s(\"%s\") hash results\n", rhash_get_name(hash_id), msg); } } }
/** * Calculate hash sums simultaneously, according to the info->sums_flags. * Calculated hashes are stored in info->rctx. * * @param info file data. The info->full_path can be "-" to denote stdin * @return 0 on success, -1 on fail with error code stored in errno */ static int calc_sums(struct file_info *info) { FILE* fd = stdin; /* stdin */ int res; uint64_t initial_size; if(IS_DASH_STR(info->full_path)) { info->print_path = "(stdin)"; #ifdef _WIN32 /* using 0 instead of _fileno(stdin). _fileno() is undefined under 'gcc -ansi' */ if(setmode(0, _O_BINARY) < 0) { return -1; } #endif } else { struct rsh_stat_struct stat_buf; /* skip non-existing files */ if(rsh_stat(info->full_path, &stat_buf) < 0) { return -1; } if((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && S_ISDIR(stat_buf.st_mode)) { errno = EISDIR; return -1; } info->size = stat_buf.st_size; /* total size, in bytes */ IF_WINDOWS(win32_set_filesize64(info->full_path, &info->size)); /* set correct filesize for large files under win32 */ if(!info->sums_flags) return 0; /* skip files opened with exclusive rights without reporting an error */ fd = rsh_fopen_bin(info->full_path, "rb"); if(!fd) { return -1; } } re_init_rhash_context(info); initial_size = info->rctx->msg_size; if(percents_output->update != 0) { rhash_set_callback(info->rctx, (rhash_callback_t)percents_output->update, info); } /* read and hash file content */ if((res = rhash_file_update(info->rctx, fd)) != -1) { if(!opt.bt_batch_file) { rhash_final(info->rctx, 0); /* finalize hashing */ } } info->size = info->rctx->msg_size - initial_size; rhash_data.total_size += info->size; if(fd != stdin) fclose(fd); return res; }
/** * Calculate hash sums simultaneously, according to the info->sums_flags. * Calculated hashes are stored in info->rctx. * * @param info file data. The info->full_path can be "-" to denote stdin * @return 0 on success, -1 on fail with error code stored in errno */ static int calc_sums(struct file_info *info) { FILE* fd = stdin; /* stdin */ int res; assert(info->file); if(info->file->mode & FILE_IFSTDIN) { info->print_path = "(stdin)"; #ifdef _WIN32 /* using 0 instead of _fileno(stdin). _fileno() is undefined under 'gcc -ansi' */ if(setmode(0, _O_BINARY) < 0) { return -1; } #endif } else { if((opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) && FILE_ISDIR(info->file)) { errno = EISDIR; return -1; } info->size = info->file->size; /* total size, in bytes */ if(!info->sums_flags) return 0; /* skip without reporting an error the files * opened exclusively by another process */ fd = rsh_fopen_bin(info->full_path, "rb"); if(!fd) { return -1; } } re_init_rhash_context(info); /* save initial msg_size, for correct calculation of percents */ info->msg_offset = info->rctx->msg_size; if(percents_output->update != 0) { rhash_set_callback(info->rctx, (rhash_callback_t)percents_output->update, info); } /* read and hash file content */ if((res = rhash_file_update(info->rctx, fd)) != -1) { if(!opt.bt_batch_file) { rhash_final(info->rctx, 0); /* finalize hashing */ } } /* calculate real file size */ info->size = info->rctx->msg_size - info->msg_offset; rhash_data.total_size += info->size; if(fd != stdin) fclose(fd); return res; }
/** * Hash a repeated message chunk by specified hash function. * * @deprecated This function shall be removed soon. * * @param hash_id hash function identifier * @param message a message chunk to hash * @param msg_size message chunk size * @param count number of chunks * @param out computed hash * @return 1 on success, 0 on error */ static int hash_in_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out) { int i; struct rhash_context *context = rhash_init(hash_id); if (!context) return 0; /* process the repeated message buffer */ for (i = 0; i < count; i++) rhash_update(context, message, msg_size); rhash_final(context, out); rhash_free(context); return 1; }
/** * Calculate hash of the message specified by chunk string, repeated until * the given length is reached. * * @param chunk a null-terminated string representing the chunk * @param msg_size the total message length * @param length the total length of the message * @param hash_id id of the hash algorithm to use */ static char* calc_sums_c(const char* chunk, size_t msg_size, size_t length, unsigned hash_id) { struct rhash_context *ctx; static char out[130]; size_t i; ctx = rhash_init(hash_id); for(i = 0; i < length; i += msg_size) { rhash_update(ctx, (const unsigned char*)chunk, ((i + msg_size) <= length ? msg_size : length % msg_size)); } rhash_final(ctx, hash_id, 0); rhash_print(out, ctx, hash_id, RHPR_UPPERCASE); rhash_free(ctx); return out; }
/** * Test printing of magnet links. */ static void test_magnet(void) { unsigned bit; rhash ctx = rhash_init(RHASH_ALL_HASHES); rhash_update(ctx, "a", 1); rhash_final(ctx, 0); assert_magnet("magnet:?xl=1&dn=test.txt&xt=urn:tree:tiger:czquwh3iyxbf5l3bgyugzhassmxu647ip2ike4y", ctx, RHASH_TTH, RHPR_FILESIZE | TEST_PATH); assert_magnet("magnet:?xl=1&xt=urn:md5:0CC175B9C0F1B6A831C399E269772661", ctx, RHASH_MD5, RHPR_FILESIZE | RHPR_UPPERCASE); assert_magnet("xt=urn:ed2k:bde52cb31de33e46245e05fbdbd6fb24&xt=urn:aich:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:sha1:q336in72uwt7zyk5dxolt2xk5i3xmz5y&xt=urn:btih:qj6nrgcg7qjs4lth4kocpbggkrb3wtob", ctx, RHASH_ED2K | RHASH_AICH | RHASH_SHA1 | RHASH_BTIH, RHPR_NO_MAGNET); /* verify length calculation for all hashes */ for(bit = 1; bit < RHASH_ALL_HASHES; bit <<= 1) { assert_magnet(NULL, ctx, bit, RHPR_FILESIZE | RHPR_NO_MAGNET); } rhash_free(ctx); }
/** * Calculate hash of the message specified by chunk string, repeated until * the given length is reached. * * @param hash_id id of the hash algorithm to use * @param msg_chunk the message chunk as a null-terminated string * @param chunk_size the size of the chunk in bytes * @param count the number of chunks in the message * @param set_filename need to set a filename for BTIH hash */ static char* repeat_hash(unsigned hash_id, const char* chunk, size_t chunk_size, size_t msg_size, int set_filename) { struct rhash_context *ctx; size_t left, size; static char out[130]; assert(rhash_get_hash_length(hash_id) < 130); ctx = rhash_init(hash_id); if((hash_id & RHASH_BTIH) && set_filename) { unsigned long long total_size = msg_size; rhash_transmit(RMSG_BT_ADD_FILE, ctx, RHASH_STR2UPTR("test.txt"), (rhash_uptr_t)&total_size); } for(left = msg_size; left > 0; left -= size) { size = (left > chunk_size ? chunk_size : left); rhash_update(ctx, (const unsigned char*)chunk, size); } rhash_final(ctx, 0); rhash_print(out, ctx, hash_id, RHPR_UPPERCASE); rhash_free(ctx); return out; }
/** * RHash program entry point. * * @param argc number of program arguments including the program path * @param argv program arguments * @return the program exit code, zero on success and 1 on error */ int main(int argc, char *argv[]) { find_file_options search_opt; timedelta_t timer; int sfv; i18n_initialize(); /* initialize locale and translation */ memset(&rhash_data, 0, sizeof(rhash_data)); rhash_data.out = stdout; /* set initial output streams */ rhash_data.log = stderr; /* can be altered by options later */ rhash_data.search_opt = &search_opt; init_hash_info_table(); read_options(argc, argv); /* load config and parse command line options */ prev_sigint_handler = signal(SIGINT, ctrl_c_handler); /* install SIGINT handler */ rhash_library_init(); /* in benchmark mode just run benchmark and exit */ if(opt.mode & MODE_BENCHMARK) { unsigned flags = (opt.flags & OPT_BENCH_RAW ? RHASH_BENCHMARK_CPB | RHASH_BENCHMARK_RAW : RHASH_BENCHMARK_CPB); if((opt.flags & OPT_BENCH_RAW) == 0) { fprintf(rhash_data.out, _("%s v%s benchmarking...\n"), PROGRAM_NAME, VERSION); } rhash_run_benchmark(opt.sum_flags, flags, rhash_data.out); rsh_exit(0); } if(opt.n_files == 0) { if(argc > 1) { log_warning(_("no files/directories were specified at command line\n")); } /* print short usage help */ log_msg(_("Usage: %s [OPTION...] <FILE>...\n\n" "Run `%s --help' for more help.\n"), CMD_FILENAME, CMD_FILENAME); rsh_exit(0); } /* setup printf formating string */ rhash_data.printf_str = opt.printf_str; if(opt.template_file) { if(!load_printf_template()) rsh_exit(2); } else if(!rhash_data.printf_str && !(opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED))) { /* initialize printf output format according to '--<hashname>' options */ init_printf_format( (rhash_data.template_text = rsh_str_new()) ); rhash_data.printf_str = rhash_data.template_text->str; if(opt.flags & OPT_VERBOSE) { char* str = rsh_strdup(rhash_data.printf_str); log_msg(_("Format string is: %s\n"), str_trim(str)); free(str); } } if(rhash_data.printf_str) { rhash_data.print_list = parse_print_string(rhash_data.printf_str, &opt.sum_flags); } memset(&search_opt, 0, sizeof(search_opt)); search_opt.max_depth = (opt.flags & OPT_RECURSIVE ? opt.find_max_depth : 0); search_opt.options = FIND_SKIP_DIRS; search_opt.call_back = find_file_callback; if((sfv = (opt.fmt == FMT_SFV && !opt.mode))) { print_sfv_banner(rhash_data.out); } /* pre-process files */ if(sfv || opt.bt_batch_file) { /* note: errors are not reported on pre-processing */ search_opt.call_back_data = (void*)1; process_files((const char**)opt.files, opt.n_files, &search_opt); fflush(rhash_data.out); } /* measure total processing time */ rhash_timer_start(&timer); rhash_data.processed = 0; /* process files */ search_opt.options |= FIND_LOG_ERRORS; search_opt.call_back_data = (void*)0; process_files((const char**)opt.files, opt.n_files, &search_opt); if((opt.mode & MODE_CHECK_EMBEDDED) && rhash_data.processed > 1) { print_check_stats(); } if(!rhash_data.interrupted) { if(opt.bt_batch_file && rhash_data.rctx) { rhash_final(rhash_data.rctx, 0); save_torrent_to(opt.bt_batch_file, rhash_data.rctx); } if((opt.flags & OPT_SPEED) && !(opt.mode & (MODE_CHECK | MODE_UPDATE)) && rhash_data.processed > 1) { double time = rhash_timer_stop(&timer); print_time_stats(time, rhash_data.total_size, 1); } } else { /* check if interruption was not reported yet */ if(rhash_data.interrupted == 1) report_interrupted(); } options_destroy(&opt); rhash_destroy(&rhash_data); /* return non-zero error code if error occurred */ return (rhash_data.error_flag ? 1 : search_opt.errors_count ? 2 : rhash_data.interrupted ? 3 : 0); }
/* * Class: org_sf_rhash_Bindings * Method: rhash_final * Signature: (J)V */ JNIEXPORT void JNICALL Java_org_sf_rhash_Bindings_rhash_1final (JNIEnv *env, jclass clz, jlong context) { rhash_final(TO_RHASH(context), NULL); }