/** * Print EDonkey 2000 url for given file to a stream. * * @param out the stream where to print url to * @param filename the file name * @param filesize the file size * @param sums the file hash sums */ static void fprint_ed2k_url(FILE* out, struct file_info *info, int print_type) { const char *filename = get_basename(file_info_get_utf8_print_path(info)); int upper_case = (print_type & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0); int len = urlencode(NULL, filename) + int_len(info->size) + (info->sums_flags & RHASH_AICH ? 84 : 49); char* buf = (char*)rsh_malloc( len + 1 ); char* dst = buf; assert(info->sums_flags & (RHASH_ED2K|RHASH_AICH)); assert(info->rctx); strcpy(dst, "ed2k://|file|"); dst += 13; dst += urlencode(dst, filename); *dst++ = '|'; sprintI64(dst, info->size, 0); dst += strlen(dst); *dst++ = '|'; rhash_print(dst, info->rctx, RHASH_ED2K, upper_case); dst += 32; if((info->sums_flags & RHASH_AICH) != 0) { strcpy(dst, "|h="); rhash_print(dst += 3, info->rctx, RHASH_AICH, RHPR_BASE32 | upper_case); dst += 32; } strcpy(dst, "|/"); fprintf(out, "%s", buf); free(buf); }
/** * Print verbose error on hash sums mismatch. * * @param info file information with path and its hash sums. */ static void print_verbose_error(struct file_info *info) { char actual[130], expected[130]; assert(HC_FAILED(info->hc.flags)); rsh_fprintf(rhash_data.out, _("ERROR")); if (HC_WRONG_FILESIZE & info->hc.flags) { sprintI64(actual, info->rctx->msg_size, 0); sprintI64(expected, info->hc.file_size, 0); rsh_fprintf(rhash_data.out, _(", size is %s should be %s"), actual, expected); } if (HC_WRONG_EMBCRC32 & info->hc.flags) { rhash_print(expected, info->rctx, RHASH_CRC32, RHPR_UPPERCASE); rsh_fprintf(rhash_data.out, _(", embedded CRC32 should be %s"), expected); } if (HC_WRONG_HASHES & info->hc.flags) { int i; unsigned reported = 0; for (i = 0; i < info->hc.hashes_num; i++) { hash_value *hv = &info->hc.hashes[i]; char *expected_hash = info->hc.data + hv->offset; unsigned hid = hv->hash_id; int pflags; if ((info->hc.wrong_hashes & (1 << i)) == 0) continue; assert(hid != 0); /* if can't detect precise hash */ if ((hid & (hid - 1)) != 0) { /* guess the hash id */ if (hid & opt.sum_flags) hid &= opt.sum_flags; if (hid & ~info->hc.found_hash_ids) hid &= ~info->hc.found_hash_ids; if (hid & ~reported) hid &= ~reported; /* avoiding repeating */ if (hid & REPORT_FIRST_MASK) hid &= REPORT_FIRST_MASK; hid &= -(int)hid; /* take the lowest bit */ } assert(hid != 0 && (hid & (hid - 1)) == 0); /* single bit only */ reported |= hid; pflags = (hv->length == (rhash_get_digest_size(hid) * 2) ? (RHPR_HEX | RHPR_UPPERCASE) : (RHPR_BASE32 | RHPR_UPPERCASE)); rhash_print(actual, info->rctx, hid, pflags); rsh_fprintf(rhash_data.out, _(", %s is %s should be %s"), rhash_get_name(hid), actual, expected_hash); } } rsh_fprintf(rhash_data.out, "\n"); }
/** * 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); } } }
/* * Class: org_sf_rhash_Bindings * Method: rhash_print * Signature: (JI)J */ JNIEXPORT jlong JNICALL Java_org_sf_rhash_Bindings_rhash_1print (JNIEnv *env, jclass clz, jlong context, jint hash_id) { Digest obj = malloc(sizeof(DigestStruct)); obj->hash_len = rhash_get_digest_size(hash_id); obj->hash_data = calloc(obj->hash_len, sizeof(unsigned char)); rhash_print((char*)obj->hash_data, TO_RHASH(context), hash_id, RHPR_RAW); return TO_JLONG(obj); }
/** * 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; }
/** * 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; }
/** * Rename given file inserting its crc32 sum enclosed into square braces * and placing it right before the file extension. * * @param info pointer to the data of the file to rename. * @return 0 on success, -1 on fail with error code in errno */ int rename_file_by_embeding_crc32(struct file_info *info) { size_t len = strlen(info->full_path); const char* p = info->full_path + len; const char* c = p - 1; char* new_path; char* insertion_point; unsigned crc32_be; assert((info->rctx->hash_id & RHASH_CRC32) != 0); /* check if the filename contains a CRC32 hash sum */ if(find_embedded_crc32(info->print_path, &crc32_be)) { unsigned char* c = (unsigned char*)rhash_get_context_ptr(info->rctx, RHASH_CRC32); unsigned actual_crc32 = ((unsigned)c[0] << 24) | ((unsigned)c[1] << 16) | ((unsigned)c[2] << 8) | (unsigned)c[3]; /* compare with calculated CRC32 */ if(crc32_be != actual_crc32) { char crc32_str[9]; rhash_print(crc32_str, info->rctx, RHASH_CRC32, RHPR_UPPERCASE); /* TRANSLATORS: sample filename with embedded CRC32: file_[A1B2C3D4].mkv */ log_warning(_("wrong embedded CRC32, should be %s\n"), crc32_str); } else return 0; } /* find file extension (as the place to insert the hash sum) */ for(; c >= info->full_path && !IS_PATH_SEPARATOR(*c); c--) { if(*c == '.') { p = c; break; } } /* now p is the point to insert delimiter + hash string in brackets */ new_path = (char*)rsh_malloc(len + 12); insertion_point = new_path + (p - info->full_path); memcpy(new_path, info->full_path, p - info->full_path); if(opt.embed_crc_delimiter && *opt.embed_crc_delimiter) *(insertion_point++) = *opt.embed_crc_delimiter; rhash_print(insertion_point+1, info->rctx, RHASH_CRC32, RHPR_UPPERCASE); insertion_point[0] = '['; insertion_point[9] = ']'; /* ']' overrides '\0' inserted by rhash_print_sum() */ strcpy(insertion_point + 10, p); /* append file extension */ /* rename the file */ if(rename(info->full_path, new_path) < 0) { log_error(_("can't move %s to %s: %s\n"), info->full_path, new_path, strerror(errno)); free(new_path); return -1; } /* change file name in the file info structure */ if(info->print_path >= info->full_path && info->print_path < p) { file_info_set_print_path(info, new_path + len - strlen(info->print_path)); } else { file_info_set_print_path(info, new_path); } free(info->full_path); info->full_path = new_path; return 0; }
/** * Print formated file information to given output stream. * * @param out the stream to print information to * @param list the format according to which information shall be printed * @param info the file information */ void print_line(FILE* out, print_item* list, struct file_info *info) { const char* basename = get_basename(info->print_path), *tmp; char *url = NULL, *ed2k_url = NULL; char buffer[130]; for(; list; list = list->next) { int print_type = list->flags & ~(PRINT_FLAGS_ALL); size_t len; /* output a hash function digest */ if(list->hash_id && print_type != PRINT_ED2K_LINK) { unsigned hash_id = list->hash_id; int print_flags = (list->flags & PRINT_FLAG_UPPERCASE ? RHPR_UPPERCASE : 0) | (list->flags & PRINT_FLAG_RAW ? RHPR_RAW : 0) | (list->flags & PRINT_FLAG_BASE32 ? RHPR_BASE32 : 0) | (list->flags & PRINT_FLAG_BASE64 ? RHPR_BASE64 : 0) | (list->flags & PRINT_FLAG_HEX ? RHPR_HEX : 0); if((hash_id == RHASH_GOST || hash_id == RHASH_GOST_CRYPTOPRO) && (opt.flags & OPT_GOST_REVERSE)) print_flags |= RHPR_REVERSE; len = rhash_print(buffer, info->rctx, hash_id, print_flags); assert(len < sizeof(buffer)); /* output the hash, exit on fail */ if(fwrite(buffer, 1, len, out) != len) break; continue; } /* output other special items: filepath, URL-encoded filename etc. */ switch(print_type) { case PRINT_STR: fprintf(out, "%s", list->data); break; case PRINT_ZERO: /* the '\0' character */ fprintf(out, "%c", 0); break; case PRINT_FILEPATH: fprintf(out, "%s", info->print_path); break; case PRINT_BASENAME: /* the filename without directory */ fprintf(out, "%s", basename); break; case PRINT_URLNAME: /* URL-encoded filename */ if(!url) { tmp = get_basename(file_info_get_utf8_print_path(info)); url = (char*)rsh_malloc(urlencode(NULL, tmp) + 1); urlencode(url, tmp); } fprintf(out, "%s", url); break; case PRINT_MTIME: /* the last-modified tine of the filename */ print_time(out, info->stat_buf.st_mtime); break; case PRINT_SIZE: /* file size */ fprintI64(out, info->size, list->width, (list->flags & PRINT_FLAG_PAD_WITH_ZERO)); break; case PRINT_ED2K_LINK: fprint_ed2k_url(out, info, list->flags); break; } } free(url); free(ed2k_url); }