Пример #1
0
void process_files(const char* paths[], size_t count,
	find_file_options* opt)
{
	struct file_t file;
	size_t i;
	memset(&file, 0, sizeof(file));

	for(i = 0; i < count && !(opt->options & FIND_CANCEL); i++) {
		file.path = (char*)paths[i];

		if(!IS_DASH_STR(file.path) && rsh_file_stat2(&file, USE_LSTAT) < 0) {
			if((opt->options & FIND_LOG_ERRORS) != 0) {
				log_file_error(file.path);
				opt->errors_count++;
			}
			continue;
		}
		if(!IS_DASH_STR(file.path) && (file.mode & FILE_IFDIR) != 0) {
			find_file(&file, opt);
		} else {
			file.mode |= FILE_ISROOT;
			opt->call_back(&file, opt->call_back_data);
		}
	}

	rsh_file_cleanup(&file);
}
Пример #2
0
/**
 * 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;
}
Пример #3
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);
	}
}
Пример #4
0
/* allocate and fill the file_search_data */
file_search_data* create_file_search_data(rsh_tchar** paths, size_t count, int max_depth)
{
	size_t i;

	file_search_data* data = (file_search_data*)rsh_malloc(sizeof(file_search_data));
	memset(data, 0, sizeof(file_search_data));
	rsh_blocks_vector_init(&data->root_files);
	data->max_depth = max_depth;

#ifdef _WIN32
	/* expand wildcards and fill the root_files */
	for (i = 0; i < count; i++)
	{
		int added = 0;
		size_t length, index;
		wchar_t* path = paths[i];
		wchar_t* p = wcschr(path, L'\0') - 1;

		/* strip trailing '\','/' symbols (if not preceded by ':') */
		for (; p > path && IS_PATH_SEPARATOR_W(*p) && p[-1] != L':'; p--) *p = 0;

		/* Expand a wildcard in the current file path and store results into data->root_files.
		 * If a wildcard is not found then just the file path is stored.
		 * NB, only wildcards in the last filename of the path are expanded. */

		length = p - path + 1;
		index = wcscspn(path, L"*?");

		if (index < length && wcscspn(path + index, L"/\\") >= (length - index))
		{
			/* a wildcard is found without a directory separator after it */
			wchar_t* parent;
			WIN32_FIND_DATAW d;
			HANDLE handle;

			/* find a directory separator before the file name */
			for (; index > 0 && !IS_PATH_SEPARATOR(path[index]); index--);
			parent = (IS_PATH_SEPARATOR(path[index]) ? path : 0);

			handle = FindFirstFileW(path, &d);
			if (INVALID_HANDLE_VALUE != handle)
			{
				do {
					file_t file;
					int failed;
					if (IS_CURRENT_OR_PARENT_DIRW(d.cFileName)) continue;

					memset(&file, 0, sizeof(file));
					file.wpath = make_pathw(parent, index + 1, d.cFileName);
					if (!file.wpath) continue;

					/* skip directories if not in recursive mode */
					if (data->max_depth == 0 && (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue;

					/* convert file name */
					file.path = wchar_to_cstr(file.wpath, WIN_DEFAULT_ENCODING, &failed);
					if (!failed) {
						failed = (file_statw(&file) < 0);
					}

					/* quietly skip unconvertible file names */
					if (!file.path || failed) {
						if (failed) {
							data->errors_count++;
						}
						free(file.path);
						free(file.wpath);
						continue;
					}

					/* fill the file information */
					file.mode |= FILE_IFROOT;
					add_root_file(data, &file);
					added++;
				} while (FindNextFileW(handle, &d));
				FindClose(handle);
			} else {
				/* report error on the specified wildcard */
				char * cpath = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, NULL);
				set_errno_from_last_file_error();
				log_file_error(cpath);
				free(cpath);
				data->errors_count++;
			}
		}
		else
		{
			int failed;
			file_t file;
			memset(&file, 0, sizeof(file));

			/* if filepath is a dash string "-" */
			if ((path[0] == L'-' && path[1] == L'\0'))
			{
				file.mode = FILE_IFSTDIN;
				file.path = rsh_strdup("(stdin)");
			} else {
				file.path = wchar_to_cstr(path, WIN_DEFAULT_ENCODING, &failed);
				if (failed) {
					log_error(_("Can't convert the path to local encoding: %s\n"), file.path);
					free(file.path);
					data->errors_count++;
					continue;
				}
				file.wpath = path;
				if (file_statw(&file) < 0) {
					log_file_error(file.path);
					free(file.path);
					data->errors_count++;
					continue;
				}
			}

			/* mark the file as obtained from the command line */
			file.mode |= FILE_IFROOT;
			file.wpath = rsh_wcsdup(path);
			add_root_file(data, &file);
		}
	} /* for */
#else
	/* copy file paths */
	for (i = 0; i < count; i++)
	{
		file_t file;
		file_init(&file, paths[i], 0);

		if (IS_DASH_STR(file.path))
		{
			file.mode = FILE_IFSTDIN;
		}
		else if (file_stat2(&file, USE_LSTAT) < 0) {
			log_file_error(file.path);
			file_cleanup(&file);
			data->errors_count++;
			continue;
		}

		file.mode |= FILE_IFROOT;
		add_root_file(data, &file);
	}
#endif
	return data;
}
Пример #5
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);
			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( IS_DASH_STR(hash_file_path) ) {
		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) {
			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 prepent 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);
			}

			/* verify hash sums of the file */
			res = verify_sums(&info);
			fflush(rhash_data.out);
			free(info.full_path);
			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);
}
Пример #6
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.full_path = rsh_strdup(file->path);
	file_info_set_print_path(&info, print_path);
	info.size = 0;

	info.sums_flags = opt.sum_flags;

	if(IS_DASH_STR(info.full_path)) {
		print_path = "(stdin)";
		memset(&info.stat_buf, 0, sizeof(info.stat_buf));
	} 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.mode & MODE_TORRENT) && !opt.bt_batch_file) {
		save_torrent(&info);
	}

	if(opt.flags & OPT_EMBED_CRC) {
		/* rename the file */
		rename_file_to_embed_crc32(&info);
	}

	if((opt.mode & MODE_UPDATE) && opt.fmt == FMT_SFV) {
		file_t file;
		file.path = info.full_path;
		file.wpath = 0;
		rsh_file_stat2(&file, 0);

		print_sfv_header_line(rhash_data.upd_fd, &file, info.full_path);
		if(opt.flags & OPT_VERBOSE) {
			print_sfv_header_line(rhash_data.log, &file, info.full_path);
			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;
}