/** * Verify hash sums of the file. * * @param info structure file path to process * @return zero on success, -1 on file error, -2 if hash sums are different */ static int verify_sums(struct file_info *info) { timedelta_t timer; int res = 0; errno = 0; /* initialize percents output */ init_percents(info); rhash_timer_start(&timer); if(calc_sums(info) < 0) { finish_percents(info, -1); return -1; } info->time = rhash_timer_stop(&timer); if(rhash_data.interrupted) { report_interrupted(); return 0; } if((opt.flags & OPT_EMBED_CRC) && find_embedded_crc32( info->print_path, &info->hc.embedded_crc32_be)) { info->hc.flags |= HC_HAS_EMBCRC32; assert(info->hc.hash_mask & RHASH_CRC32); } if(!hash_check_verify(&info->hc, info->rctx)) { res = -2; } finish_percents(info, res); if((opt.flags & OPT_SPEED) && info->sums_flags) { print_file_time_stats(info); } return res; }
/** * Calculate and print file hash sums using printf format. * * @param out a stream to print to * @param file the file to calculate sums for * @param print_path the path to print * @return 0 on success, -1 on fail */ int calculate_and_print_sums(FILE* out, file_t* file, const char *print_path) { struct file_info info; timedelta_t timer; int res = 0; memset(&info, 0, sizeof(info)); info.file = file; info.full_path = rsh_strdup(file->path); file_info_set_print_path(&info, print_path); info.size = 0; info.sums_flags = opt.sum_flags; if(file->mode & FILE_IFSTDIN) { print_path = "(stdin)"; } else { if(file->mode & FILE_IFDIR) return 0; /* don't handle directories */ info.size = file->size; /* total size, in bytes */ } /* initialize percents output */ init_percents(&info); rhash_timer_start(&timer); if(info.sums_flags) { /* calculate sums */ if(calc_sums(&info) < 0) { /* print error unless sharing access error occurred */ if(errno == EACCES) return 0; log_file_error(file->path); res = -1; } if(rhash_data.interrupted) { report_interrupted(); return 0; } } info.time = rhash_timer_stop(&timer); finish_percents(&info, res); if(opt.flags & OPT_EMBED_CRC) { /* rename the file */ rename_file_by_embeding_crc32(&info); } if((opt.mode & MODE_TORRENT) && !opt.bt_batch_file) { save_torrent(&info); } if((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) { /* updating SFV file: print SFV header line */ print_sfv_header_line(rhash_data.upd_fd, file, 0); if(opt.flags & OPT_VERBOSE) { print_sfv_header_line(rhash_data.log, file, 0); fflush(rhash_data.log); } rsh_file_cleanup(file); } if(rhash_data.print_list && res >= 0) { if (!opt.bt_batch_file) { print_line(out, rhash_data.print_list, &info); fflush(out); /* print calculated line to stderr or log-file if verbose */ if((opt.mode & MODE_UPDATE) && (opt.flags & OPT_VERBOSE)) { print_line(rhash_data.log, rhash_data.print_list, &info); fflush(rhash_data.log); } } if((opt.flags & OPT_SPEED) && info.sums_flags) { print_file_time_stats(&info); } } free(info.full_path); file_info_destroy(&info); return res; }
/** * 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); }