/** * (Re)-initialize RHash context, to calculate hash sums. * * @param info the file data */ static void re_init_rhash_context(struct file_info *info) { if(rhash_data.rctx != 0) { if(opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) { /* a set of hash sums can change from file to file */ rhash_free(rhash_data.rctx); rhash_data.rctx = 0; } else { info->rctx = rhash_data.rctx; if(!opt.bt_batch_file) { rhash_reset(rhash_data.rctx); } else { /* add another file to the torrent batch */ rhash_transmit(RMSG_BT_ADD_FILE, rhash_data.rctx, RHASH_STR2UPTR((char*)file_info_get_utf8_print_path(info)), (rhash_uptr_t)&info->size); return; } } } if(rhash_data.rctx == 0) { info->rctx = rhash_data.rctx = rhash_init(info->sums_flags); } /* re-initialize BitTorrent data */ if(info->sums_flags & RHASH_BTIH) { init_btih_data(info); } }
/** * Save torrent file to the given path. * * @param path the path to save torrent file to * @param rctx the context containing torrent data */ void save_torrent_to(const char* path, rhash_context* rctx) { FILE* fd; struct rsh_stat_struct stat_buf; size_t text_len; char *str; /* get torrent file content */ text_len = rhash_transmit(RMSG_BT_GET_TEXT, rctx, RHASH_STR2UPTR(&str), 0); assert(text_len != RHASH_ERROR); if(rsh_stat(path, &stat_buf) >= 0) { /* make backup copy of the existing torrent file */ char *bak_path = str_append(path, ".bak"); unlink(bak_path); rename(path, bak_path); free(bak_path); } /* write torrent file */ fd = rsh_fopen_bin(path, "wb"); if(fd && text_len == fwrite(str, 1, text_len, fd) && !ferror(fd) && !fflush(fd)) { log_msg(_("%s saved\n"), path); } else { log_file_error(path); } if(fd) fclose(fd); }
/** * 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); } } }
/** * Check that options do not conflict with each other. * Also make some final options processing steps. */ static void make_final_options_checks(void) { unsigned ff; /* formating flags */ if((opt.flags & OPT_VERBOSE) && conf_opt.config_file) { /* note that the first log_msg call shall be made after setup_output() */ log_msg(_("Config file: %s\n"), (conf_opt.config_file ? conf_opt.config_file : _("None"))); } if(opt.bt_batch_file) opt.mode |= MODE_TORRENT; if(opt.mode & MODE_TORRENT) opt.sum_flags |= RHASH_BTIH; /* check that no more than one program mode specified */ if(opt.mode & (opt.mode - 1)) { die(_("incompatible program modes\n")); } ff = (opt.printf_str ? 1 : 0) | (opt.template_file ? 2 : 0) | (opt.fmt ? 4 : 0); if((opt.fmt & (opt.fmt - 1)) || (ff & (ff - 1))) { die(_("too many formating options\n")); } if(!opt.crc_accept) opt.crc_accept = file_mask_new_from_list(".sfv"); if(opt.openssl_mask) rhash_transmit(RMSG_SET_OPENSSL_MASK, 0, opt.openssl_mask, 0); }
/** * 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; }
/** * Initialize BTIH hash function. Unlike other algorithms BTIH * requires more data for correct computation. * * @param info the file data */ static void init_btih_data(struct file_info *info) { assert((info->rctx->hash_id & RHASH_BTIH) != 0); rhash_transmit(RMSG_BT_ADD_FILE, info->rctx, RHASH_STR2UPTR((char*)file_info_get_utf8_print_path(info)), (rhash_uptr_t)&info->size); rhash_transmit(RMSG_BT_SET_PROGRAM_NAME, info->rctx, RHASH_STR2UPTR(PROGRAM_NAME "/" VERSION), 0); if(opt.flags & OPT_BT_PRIVATE) { rhash_transmit(RMSG_BT_SET_OPTIONS, info->rctx, RHASH_BT_OPT_PRIVATE, 0); } if(opt.bt_announce) { rhash_transmit(RMSG_BT_SET_ANNOUNCE, info->rctx, RHASH_STR2UPTR(opt.bt_announce), 0); } if(opt.bt_piece_length) { rhash_transmit(RMSG_BT_SET_PIECE_LENGTH, info->rctx, RHASH_STR2UPTR(opt.bt_piece_length), 0); } else if(opt.bt_batch_file && rhash_data.batch_size) { rhash_transmit(RMSG_BT_SET_BATCH_SIZE, info->rctx, RHASH_STR2UPTR(&rhash_data.batch_size), 0); } }