/** * 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"); }
/** * 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); }
/** * Output aligned uint64_t number to specified output stream. * * @param out the stream to output to * @param filesize the 64-bit integer to output, usually a file size * @param width minimal width of integer to output * @param flag =1 if the integer shall be prepent by zeros */ static void fprintI64(FILE* out, uint64_t filesize, int width, int zero_pad) { char *buf = (char*)rsh_malloc(width > 40 ? width + 1 : 41); int len = int_len(filesize); sprintI64(buf, filesize, width); if(len < width && zero_pad) { memset(buf, '0', width-len); } fprintf(out, "%s", buf); free(buf); }
/** * B-encode given integer. * * @param out the string buffer to output encoded integer to * @param number the integer to output */ static void bt_bencode_int(strbuf_t *out, uint64_t number) { char* p; /* add up to 20 digits and 2 letters */ str_ensure_size(out, out->len + 22); p = out->str + out->len; *(p++) = 'i'; p += sprintI64(p, number); *(p++) = 'e'; *p = '\0'; /* terminate string with \0 */ out->len = (p - out->str); }
/** * B-encode a string. * * @param out the string buffer to put encoded string into * @param str the string to encode */ static void bt_bencode_str(strbuf_t *out, const char* str) { size_t len = strlen(str); int num_len; char* p; str_ensure_size(out, out->len + len + 21); p = out->str + out->len; p += (num_len = sprintI64(p, len)); out->len += len + num_len + 1; *(p++) = ':'; memcpy(p, str, len + 1); /* copy with trailing '\0' */ }
/** * B-encode array of SHA1 hashes of file pieces. * * @param out the string buffer to put encoded array into * @param ctx pointer to the torrent structure containing hashes */ static void bt_bencode_pieces(strbuf_t *out, torrent_ctx* ctx) { int pieces_length = ctx->blocks_hashes.size * BT_HASH_SIZE; int num_len; int size, i; char* p; str_ensure_size(out, out->len + pieces_length + 21); p = out->str + out->len; p += (num_len = sprintI64(p, pieces_length)); out->len += pieces_length + num_len + 1; *(p++) = ':'; p[pieces_length] = '\0'; /* terminate with \0 just in case */ for(size = ctx->blocks_hashes.size, i = 0; size > 0; size -= BT_BLOCK_SIZE, i++) { memcpy(p, ctx->blocks_hashes.blocks.array[i], (size < BT_BLOCK_SIZE ? size : BT_BLOCK_SIZE) * BT_HASH_SIZE); p += BT_BLOCK_SIZE * BT_HASH_SIZE; } }
/** * Print a file info line in SFV header format. * * @param out a stream to print info to * @param file the file info to print * @return 0 on success, -1 on fail with error code stored in errno */ int print_sfv_header_line(FILE* out, file_t* file, const char* printpath) { char buf[24]; if(!printpath) printpath = file->path; if(printpath[0] == '.' && IS_PATH_SEPARATOR(printpath[1])) printpath += 2; #ifdef _WIN32 /* skip file if it can't be opened with exclusive sharing rights */ if(!can_open_exclusive(file->path)) { return 0; } #endif sprintI64(buf, file->size, 12); fprintf(out, "; %s ", buf); print_time64(out, file->mtime); fprintf(out, " %s\n", printpath); return 0; }