Esempio n. 1
0
/**
 * Hash, check or update files according to work mode.
 */
static void process_files(void)
{
	timedelta_t timer;
	struct rsh_stat_struct stat_buf;
	int i;
	rhash_timer_start(&timer);
	rhash_data.processed = 0;

	/* process filenames */
	for(i = 0; i < opt.n_files; i++) {
		int res = 0;
		char* filepath = opt.files[i];
		stat_buf.st_mode = 0;

		if(!IS_DASH_STR(filepath) && rsh_stat(filepath, &stat_buf) < 0) {
			log_file_error(filepath);
			continue;
		}
		if(opt.flags & OPT_RECURSIVE) {
			if(S_ISDIR(stat_buf.st_mode)) {
				find_file(filepath, find_file_callback, 0, opt.find_max_depth, NULL);
				continue;
			}
		} else {
			if(S_ISDIR(stat_buf.st_mode)){
				if(opt.flags & OPT_VERBOSE){
					log_warning(_("%s: is a directory\n"), filepath);
				}
				continue;
			}
		}

		if(opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) {
			res = check_hash_file(filepath, 0);
		} else if(opt.mode & MODE_UPDATE) {
			res = update_hash_file(filepath);
		} else {
			res = calculate_and_print_sums(rhash_data.out, filepath, filepath, &stat_buf);
			rhash_data.processed++;
		}
		if(res < 0) rhash_data.error_flag = 1;
	}

	if((opt.mode & MODE_CHECK_EMBEDDED) && rhash_data.processed > 1) {
		print_check_stats();
	}

	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);
	}
}
Esempio n. 2
0
/**
 * 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;
}
Esempio n. 3
0
/**
 * 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);
}
Esempio n. 4
0
/**
 * 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;
}
Esempio n. 5
0
/**
 * 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);
}
Esempio n. 6
0
/**
 * Benchmark a hash algorithm.
 *
 * @deprecated This function shall be removed soon, since
 * it is not related to the hashing library main functionality.
 *
 * @param hash_id hash algorithm identifier
 * @param flags benchmark flags, can be RHASH_BENCHMARK_QUIET and RHASH_BENCHMARK_CPB
 * @param output the stream to print results
 */
void rhash_run_benchmark(unsigned hash_id, unsigned flags, FILE* output)
{
	unsigned char ALIGN_ATTR(16) message[8192]; /* 8 KiB */
	timedelta_t timer;
	int i, j;
	size_t sz_mb, msg_size;
	double time, total_time = 0;
	const int rounds = 4;
	const char* hash_name;
	unsigned char out[130];
#ifdef HAVE_TSC
	double cpb = 0;
#endif /* HAVE_TSC */

#ifdef _WIN32
	benchmark_cpu_init(); /* set cpu affinity to improve test results */
#endif

	/* set message size for fast and slow hash functions */
	msg_size = 1073741824 / 2;
	if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) {
		msg_size /= 8;
	} else if (hash_id & (RHASH_GOST | RHASH_GOST_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) {
		msg_size /= 2;
	}
	sz_mb = msg_size / (1 << 20); /* size in MiB */
	hash_name = rhash_get_name(hash_id);
	if (!hash_name) hash_name = ""; /* benchmarking several hashes*/

	for (i = 0; i < (int)sizeof(message); i++) message[i] = i & 0xff;

	for (j = 0; j < rounds; j++) {
		rhash_timer_start(&timer);
		hash_in_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out);

		time = rhash_timer_stop(&timer);
		total_time += time;

		if ((flags & (RHASH_BENCHMARK_QUIET | RHASH_BENCHMARK_RAW)) == 0) {
			fprintf(output, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time);
			fflush(output);
		}
	}

#if defined(HAVE_TSC)
	/* measure the CPU "clocks per byte" speed */
	if (flags & RHASH_BENCHMARK_CPB) {
		unsigned int c1 = -1, c2 = -1;
		unsigned volatile long long cy0, cy1, cy2;
		int msg_size = 128 * 1024;

		/* make 200 tries */
		for (i = 0; i < 200; i++) {
			cy0 = read_tsc();
			hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
			cy1 = read_tsc();
			hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
			hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
			cy2 = read_tsc();

			cy2 -= cy1;
			cy1 -= cy0;
			c1 = (unsigned int)(c1 > cy1 ? cy1 : c1);
			c2 = (unsigned int)(c2 > cy2 ? cy2 : c2);
		}
		cpb = ((c2 - c1) + 1) / (double)msg_size;
	}
#endif /* HAVE_TSC */

	if (flags & RHASH_BENCHMARK_RAW) {
		/* output result in a "raw" machine-readable format */
		fprintf(output, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
#if defined(HAVE_TSC)
		if (flags & RHASH_BENCHMARK_CPB) fprintf(output, "\t%.2f", cpb);
#endif /* HAVE_TSC */
		fprintf(output, "\n");
	} else {
		fprintf(output, "%s %u MiB total in %.3f sec, %.3f MBps", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
#if defined(HAVE_TSC)
		if (flags & RHASH_BENCHMARK_CPB) fprintf(output, ", CPB=%.2f", cpb);
#endif /* HAVE_TSC */
		fprintf(output, "\n");
	}
}