/** * 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); }
/** * 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; }
/** * Check hash sums in a hash file. * Lines beginning with ';' and '#' are ignored. * * @param hash_file_path - the path of the file with hash sums to verify. * @param chdir - true if function should emulate chdir to directory of filepath before checking it. * @return zero on success, -1 on fail */ int check_hash_file(file_t* file, int chdir) { FILE *fd; char buf[2048]; size_t pos; const char *ralign; timedelta_t timer; struct file_info info; const char* hash_file_path = file->path; int res = 0, line_num = 0; double time; /* process --check-embedded option */ if(opt.mode & MODE_CHECK_EMBEDDED) { unsigned crc32_be; if(find_embedded_crc32(hash_file_path, &crc32_be)) { /* initialize file_info structure */ memset(&info, 0, sizeof(info)); info.full_path = rsh_strdup(hash_file_path); info.file = file; file_info_set_print_path(&info, info.full_path); info.sums_flags = info.hc.hash_mask = RHASH_CRC32; info.hc.flags = HC_HAS_EMBCRC32; info.hc.embedded_crc32_be = crc32_be; res = verify_sums(&info); fflush(rhash_data.out); if(!rhash_data.interrupted) { if(res == 0) rhash_data.ok++; else if(res == -1 && errno == ENOENT) rhash_data.miss++; rhash_data.processed++; } free(info.full_path); file_info_destroy(&info); } else { log_warning(_("file name doesn't contain a CRC32: %s\n"), hash_file_path); return -1; } return 0; } /* initialize statistics */ rhash_data.processed = rhash_data.ok = rhash_data.miss = 0; rhash_data.total_size = 0; if(file->mode & FILE_IFSTDIN) { fd = stdin; hash_file_path = "<stdin>"; } else if( !(fd = rsh_fopen_bin(hash_file_path, "rb") )) { log_file_error(hash_file_path); return -1; } pos = strlen(hash_file_path)+16; ralign = str_set(buf, '-', (pos < 80 ? 80 - (int)pos : 2)); fprintf(rhash_data.out, _("\n--( Verifying %s )%s\n"), hash_file_path, ralign); fflush(rhash_data.out); rhash_timer_start(&timer); /* mark the directory part of the path, by setting the pos index */ if(chdir) { pos = strlen(hash_file_path); for(; pos > 0 && !IS_PATH_SEPARATOR(hash_file_path[pos]); pos--); if(IS_PATH_SEPARATOR(hash_file_path[pos])) pos++; } else pos = 0; /* read crc file line by line */ for(line_num = 0; fgets(buf, 2048, fd); line_num++) { char* line = buf; char* path_without_ext = NULL; /* skip unicode BOM */ if(line_num == 0 && buf[0] == (char)0xEF && buf[1] == (char)0xBB && buf[2] == (char)0xBF) line += 3; if(*line == 0) continue; /* skip empty lines */ if(is_binary_string(line)) { log_error(_("file is binary: %s\n"), hash_file_path); if(fd != stdin) fclose(fd); return -1; } /* skip comments and empty lines */ if(IS_COMMENT(*line) || *line == '\r' || *line == '\n') continue; memset(&info, 0, sizeof(info)); if(!hash_check_parse_line(line, &info.hc, !feof(fd))) continue; if(info.hc.hash_mask == 0) continue; info.print_path = info.hc.file_path; info.sums_flags = info.hc.hash_mask; /* see if crc file contains a hash sum without a filename */ if(info.print_path == NULL) { char* point; path_without_ext = rsh_strdup(hash_file_path); point = strrchr(path_without_ext, '.'); if(point) { *point = '\0'; file_info_set_print_path(&info, path_without_ext); } } if(info.print_path != NULL) { file_t file_to_check; int is_absolute = IS_PATH_SEPARATOR(info.print_path[0]); IF_WINDOWS(is_absolute = is_absolute || (info.print_path[0] && info.print_path[1] == ':')); /* if filename shall be prepended by a directory path */ if(pos && !is_absolute) { size_t len = strlen(info.print_path); info.full_path = (char*)rsh_malloc(pos + len + 1); memcpy(info.full_path, hash_file_path, pos); strcpy(info.full_path + pos, info.print_path); } else { info.full_path = rsh_strdup(info.print_path); } memset(&file_to_check, 0, sizeof(file_t)); file_to_check.path = info.full_path; rsh_file_stat(&file_to_check); info.file = &file_to_check; /* verify hash sums of the file */ res = verify_sums(&info); fflush(rhash_data.out); rsh_file_cleanup(&file_to_check); file_info_destroy(&info); if(rhash_data.interrupted) { free(path_without_ext); break; } /* update statistics */ if(res == 0) rhash_data.ok++; else if(res == -1 && errno == ENOENT) rhash_data.miss++; rhash_data.processed++; } free(path_without_ext); } time = rhash_timer_stop(&timer); fprintf(rhash_data.out, "%s\n", str_set(buf, '-', 80)); print_check_stats(); if(rhash_data.processed != rhash_data.ok) rhash_data.error_flag = 1; if(opt.flags & OPT_SPEED && rhash_data.processed > 1) { print_time_stats(time, rhash_data.total_size, 1); } rhash_data.processed = 0; res = ferror(fd); /* check that crc file has been read without errors */ if(fd != stdin) fclose(fd); return (res == 0 ? 0 : -1); }