示例#1
0
/**
 * Assemble a filepath from its directory and filename.
 *
 * @param dir_path directory path
 * @param filename file name
 * @return filepath
 */
char* make_path(const char* dir_path, const char* filename)
{
	char* buf;
	size_t len;
	assert(dir_path);
	assert(filename);

	/* remove leading path separators from filename */
	while (IS_PATH_SEPARATOR(*filename)) filename++;

	if (dir_path[0] == '.' && dir_path[1] == 0) {
		/* do not extend filename for dir_path="." */
		return rsh_strdup(filename);
	}

	/* copy directory path */
	len = strlen(dir_path);
	buf = (char*)rsh_malloc(len + strlen(filename) + 2);
	strcpy(buf, dir_path);

	/* separate directory from filename */
	if (len > 0 && !IS_PATH_SEPARATOR(buf[len-1])) {
		buf[len++] = SYS_PATH_SEPARATOR;
	}

	/* append filename */
	strcpy(buf+len, filename);
	return buf;
}
示例#2
0
/**
 * Convert given string to lower case.
 * The result string will be allocated by malloc.
 * The allocated memory should be freed by calling free().
 *
 * @param str a string to convert
 * @return converted string allocated by malloc
 */
char* str_tolower(const char* str)
{
	char* buf = rsh_strdup(str);
	char* p;
	if (buf) {
		for (p = buf; *p; p++) *p = tolower(*p);
	}
	return buf;
}
示例#3
0
/**
 * Allocate new print_item.
 *
 * @param flags the print_item flags
 * @param hash_id optional hash_id
 * @param data optional string to store
 * @return allocated print_item
 */
static print_item* new_print_item(unsigned flags, unsigned hash_id, const char *data)
{
	print_item* item = (print_item*)rsh_malloc(sizeof(print_item));
	item->flags = flags;
	item->hash_id = hash_id;
	item->width = 0;
	item->data = (data ? rsh_strdup(data) : NULL);
	item->next = NULL;
	return item;
}
示例#4
0
void file_init(file_t* file, const char* path, int reuse_path)
{
	memset(file, 0, sizeof(*file));
	if (reuse_path)
	{
		file->path = (char*)path;
		file->mode = FILE_OPT_DONT_FREE_PATH;
	} else {
		file->path = rsh_strdup(path);
	}
}
示例#5
0
/**
 * Convert given C-string from encoding specified by
 * command line options to utf8.
 *
 * @param str the string to convert
 * @return converted string on success, NULL on fail
 */
char* win_to_utf8(const char* str)
{
	char* res;
	wchar_t* buf;

	assert((opt.flags & (OPT_UTF8 | OPT_OEM | OPT_ANSI)) != 0);
	if(opt.flags & OPT_UTF8) return rsh_strdup(str);

	if((buf = c2w(str, 0)) == NULL) return NULL;
	res = wchar_to_cstr(buf, CP_UTF8, NULL);
	free(buf);
	return res;
}
示例#6
0
/**
 * Return allocated buffer with the directory part of the path.
 * The buffer must be freed by calling free().
 *
 * @param path file path
 * @return directory
 */
char* get_dirname(const char* path)
{
	const char *p = path + strlen(path) - 1;
	char *res;
	for (; p > path && !IS_PATH_SEPARATOR(*p); p--);
	if ((p - path) > 1) {
		res = (char*)rsh_malloc(p-path+1);
		memcpy(res, path, p-path);
		res[p-path] = 0;
		return res;
	} else {
		return rsh_strdup(".");
	}
}
示例#7
0
文件: file_mask.c 项目: 0-wiz-0/RHash
/**
 * Split the given string by comma and put the parts into array.
 *
 * @param vect the array to put the parsed elements to
 * @param comma_separated_list the string to split
 */
void file_mask_add_list(file_mask_array* vect, const char* comma_separated_list)
{
	char *buf, *cur, *next;
	if (!comma_separated_list || !*comma_separated_list) {
		return;
	}
	buf = rsh_strdup(comma_separated_list);
	for (cur = buf; cur && *cur; cur = next) {
		next = strchr(cur, ',');
		if (next) *(next++) = '\0';
		if (*cur != '\0') file_mask_add(vect, cur);
	}
	free(buf);
}
示例#8
0
/**
 * Set file path of the given item.
 *
 * @param item pointer to the item to change
 * @param filepath the file path to set
 */
static int file_set_item_set_filepath(file_set_item* item, const char* filepath)
{
	if(item->search_filepath != item->filepath)
		free(item->search_filepath);
	free(item->filepath);
	item->filepath = rsh_strdup(filepath);
	if(!item->filepath) return 0;

	/* apply str_tolower if CASE_INSENSITIVE */
	/* Note: strcasecmp() is not used instead of search_filepath due to portability issue */
	/* Note: item->search_filepath is always correctly freed by file_set_item_free() */
	item->search_filepath = (opt.flags & OPT_IGNORE_CASE ? str_tolower(item->filepath) : item->filepath);
	item->hash = file_set_make_hash(item->search_filepath);
	return 1;
}
示例#9
0
/**
 * Allocate and initialize a dir_entry.
 *
 * @param next next dir_entry in list
 * @param filename a filename to store in the dir_entry
 * @param type type of dir_entry
 * @return allocated dir_entry
 */
static dir_entry* dir_entry_new(dir_entry *next, char* filename, unsigned type)
{
	dir_entry* e = (dir_entry*)malloc(sizeof(dir_entry));
	if (!e) return NULL;
	if (filename) {
		e->filename = rsh_strdup(filename);
		if (!e->filename) {
			free(e);
			return NULL;
		}
	} else {
		e->filename = NULL;
	}
	e->next = next;
	e->type = type;
	return e;
}
示例#10
0
文件: calc_sums.c 项目: 0-wiz-0/RHash
/**
 * Store print_path in a file_info struct, replacing if needed
 * system path separators with specified by user command line option.
 *
 * @param info pointer to the the file_info structure to change
 * @param print_path the print path to store
 */
static void file_info_set_print_path(struct file_info* info, const char* print_path)
{
	char *p;
	char wrong_sep;

	/* check if path separator was specified by command line options */
	if(opt.path_separator) {
		wrong_sep = (opt.path_separator == '/' ? '\\' : '/');
		if((p = (char*)strchr(print_path, wrong_sep)) != NULL) {
			info->allocated_ptr = rsh_strdup(print_path);
			info->print_path = info->allocated_ptr;
			p = info->allocated_ptr + (p - print_path);

			/* replace wrong_sep in the print_path with separator defined by options */
			for(; *p; p++) {
				if(*p == wrong_sep) *p = opt.path_separator;
			}
			return;
		}
	}

	/* if path was not replaces, than just store the value */
	info->print_path = print_path;
}
示例#11
0
/**
 * Set optional name of the program generating the torrent
 * for storing into torrent file.
 *
 * @param ctx the torrent algorithm context
 * @param name the program name
 */
void torrent_set_program_name(torrent_ctx *ctx, const char* name)
{
  ctx->program_name = rsh_strdup(name);
}
示例#12
0
文件: calc_sums.c 项目: 0-wiz-0/RHash
/**
 * 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;
}
示例#13
0
/**
 * Walk directory tree and call given callback function to process each file/directory.
 *
 * @param start_dir path to the directory to walk recursively
 * @param data the options specifying how to walk the directory tree
 * @return 0 on success, -1 on error
 */
static int dir_scan(file_t* start_dir, file_search_data* data)
{
	dir_entry *dirs_stack = NULL; /* root of the dir_list */
	dir_iterator* it;
	int level = 0;
	int max_depth = data->max_depth;
	int options = data->options;
	file_t file;

	if (max_depth < 0 || max_depth >= MAX_DIRS_DEPTH) {
		max_depth = MAX_DIRS_DEPTH - 1;
	}

	/* skip the directory if max_depth == 0 */
	if (!max_depth) return 0;

	if (!FILE_ISDIR(start_dir)) {
		errno = ENOTDIR;
		return -1;
	}

	/* check if we should descend into the root directory */
	if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == 0) {
		if (!data->call_back(start_dir, data->call_back_data))
			return 0;
	}

	/* allocate array of counters of directory elements */
	it = (dir_iterator*)malloc((MAX_DIRS_DEPTH + 1) * sizeof(dir_iterator));
	if (!it) {
		return -1;
	}

	/* push dummy counter for the root element */
	it[0].count = 1;
	it[0].dir_path = 0;

	memset(&file, 0, sizeof(file));

	while (!(data->options & FIND_CANCEL))
	{
		dir_entry **insert_at;
		char* dir_path;
		DIR *dp;
		struct dirent *de;

		/* climb down from the tree */
		while (--it[level].count < 0) {
			/* do not need this dir_path anymore */
			free(it[level].dir_path);

			if (--level < 0) {
				/* walked the whole tree */
				assert(!dirs_stack);
				free(it);
				return 0;
			}
		}
		assert(level >= 0 && it[level].count >= 0);

		/* take a filename from dirs_stack and construct the next path */
		if (level) {
			assert(dirs_stack != NULL);
			dir_path = make_path(it[level].dir_path, dirs_stack->filename);
			dir_entry_drop_head(&dirs_stack);
		} else {
			/* the first cycle: start from a root directory */
			dir_path = rsh_strdup(start_dir->path);
		}

		if (!dir_path) continue;

		/* fill the next level of directories */
		level++;
		assert(level < MAX_DIRS_DEPTH);
		it[level].count = 0;
		it[level].dir_path = dir_path;

		if ((options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == FIND_WALK_DEPTH_FIRST)
		{
			int res;
			file_init(&file, dir_path, 1);
			res = file_stat2(&file, USE_LSTAT);

			/* check if we should skip the directory */
			if (res < 0 || !data->call_back(&file, data->call_back_data)) {
				if (res < 0 && (options & FIND_LOG_ERRORS)) {
					data->errors_count++;
				}
				file_cleanup(&file);
				continue;
			}
		}
		file_cleanup(&file);

		/* step into directory */
		dp = opendir(dir_path);
		if (!dp) continue;

		insert_at = &dirs_stack;

		while ((de = readdir(dp)) != NULL)
		{
			int res;

			/* skip the "." and ".." directories */
			if (IS_CURRENT_OR_PARENT_DIR(de->d_name)) continue;

			file.mode = 0;
			file.path = make_path(dir_path, de->d_name);
			if (!file.path) continue;

			res  = file_stat2(&file, USE_LSTAT);
			if (res >= 0) {
				/* process the file or directory */
				if (FILE_ISDIR(&file) && (options & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS))) {
					res = ((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file));
				} else if (FILE_ISREG(&file)) {
					/* handle file by callback function */
					res = data->call_back(&file, data->call_back_data);
				}

				/* check if file is a directory and we need to walk it, */
				/* but don't go deeper than max_depth */
				if (FILE_ISDIR(&file) && res && level < max_depth &&
					((options & FIND_FOLLOW_SYMLINKS) || !FILE_ISLNK(&file)))
				{
					/* add the directory name to the dirs_stack */
					if (dir_entry_insert(insert_at, de->d_name, file.mode)) {
						/* the directory name was successfully inserted */
						insert_at = &((*insert_at)->next);
						it[level].count++;
					}
				}
			} else if (options & FIND_LOG_ERRORS) {
				/* report error only if FIND_LOG_ERRORS option is set */
				log_file_error(file.path);
				data->errors_count++;
			}
			file_cleanup(&file);
		}
		closedir(dp);
	}

	while (dirs_stack) {
		dir_entry_drop_head(&dirs_stack);
	}
	while (level) {
		free(it[level--].dir_path);
	}
	free(it);
	assert(file.path == 0);
	return 0;
}
示例#14
0
/**
 * Walk directory tree and call given callback function to process each file/directory.
 *
 * @param start_dir path to the directory to walk recursively
 * @param options the options specifying how to walk the directory tree
 */
int find_file(file_t* start_dir, find_file_options* options)
{
	dir_entry *dirs_stack = NULL; /* root of the dir_list */
	dir_iterator* it;
	int level = 1;
	int max_depth = options->max_depth;
	int flags = options->options;
	dir_entry* entry;
	file_t file;

	if(max_depth < 0 || max_depth >= MAX_DIRS_DEPTH) {
		max_depth = MAX_DIRS_DEPTH;
	}

	/* skip the directory if max_depth == 0 */
	if(max_depth == 0) {
		return 0;
	}

	memset(&file, 0, sizeof(file));

	if((start_dir->mode & FILE_IFDIR) == 0) {
		errno = ENOTDIR;
		return -1;
	}

	/* check if we should descend into the root directory */
	if((flags & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS)) == 0) {
		if(!options->call_back(start_dir, options->call_back_data))
			return 0;
	}

	it = (dir_iterator*)malloc(MAX_DIRS_DEPTH * sizeof(dir_iterator));
	if(!it) return 0;

	/* push root directory into dirs_stack */
	it[0].left = 1;
	it[0].prev_dir = rsh_strdup(start_dir->path);
	it[1].prev_dir = NULL;
	if(!it[0].prev_dir) {
		errno = ENOMEM;
		return -1;
	}
	entry = dir_entry_insert(&dirs_stack, NULL, 0);
	if(!entry) {
		free(it[0].prev_dir);
		free(it);
		errno = ENOMEM;
		return -1;
	}

	while(!(options->options & FIND_CANCEL)) {
		dir_entry *dir, **insert_at;
		char* dir_path;
		DIR *dp;
		struct dirent *de;

		/* walk back */
		while((--level) >= 0 && it[level].left <= 0) free(it[level+1].prev_dir);
		if(level < 0) break;
		assert(dirs_stack != NULL);
		/* on the first cycle: level == 0, stack[0] == 0; */

		dir = dirs_stack; /* take last dir from the list */
		dirs_stack = dirs_stack->next; /* remove last dir from the list */
		it[level].left--;

		dir_path = (!dir->filename ? rsh_strdup(it[level].prev_dir) :
			make_path(it[level].prev_dir, dir->filename) );
		dir_entry_free(dir);
		if(!dir_path) continue;

		level++;
		it[level].left = 0;
		it[level].prev_dir = dir_path;

		if((flags & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS))
			== FIND_WALK_DEPTH_FIRST) {
			rsh_file_cleanup(&file);
			file.path = dir_path;
			/* check if we should skip the directory */
			if(!options->call_back(&file, options->call_back_data))
				continue;
		}

		/* read dir */
		dp = opendir(dir_path);
		if(dp == NULL) continue;

		insert_at = &dirs_stack;

		while((de = readdir(dp)) != NULL) {
			int res;
			/* skip "." and ".." dirs */
			if(de->d_name[0] == '.' && (de->d_name[1] == 0 ||
				(de->d_name[1] == '.' && de->d_name[2] == 0 )))
				continue;

			if( !(file.path = make_path(dir_path, de->d_name)) ) continue;

			res  = rsh_file_stat2(&file, USE_LSTAT);
			/* process */
			if(res >= 0) {
				if((file.mode & FILE_IFDIR) &&
					(flags & (FIND_WALK_DEPTH_FIRST | FIND_SKIP_DIRS))) res = 1;
				else {
					/* handle file by callback function */
					res = options->call_back(&file, options->call_back_data);
				}

				/* if file is a directory and we need to walk it */
				if((file.mode & FILE_IFDIR) && res && level < max_depth) {
					/* don't go deeper if max_depth reached */

					/* add directory to dirs_stack */
					if(dir_entry_insert(insert_at, de->d_name, file.mode)) {
						/* if really added */
						insert_at = &((*insert_at)->next);
						it[level].left++;
					}
				}
			} else if (options->options & FIND_LOG_ERRORS) {
				log_file_error(file.path);
			}
			rsh_file_cleanup(&file);
			free(file.path);
		}
		closedir(dp);

		if(it[level].left > 0) level++;
	}
	assert(dirs_stack == NULL);

	free(it);
	return 0;
}
示例#15
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[])
{
	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 */

	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);
	}

	preprocess_files();
	process_files();

	options_destroy(&opt);
	rhash_destroy(&rhash_data);
	return (rhash_data.error_flag ? 1 : 0);
}
示例#16
0
/**
 * Set torrent announcement-url for storing into torrent file.
 *
 * @param ctx the torrent algorithm context
 * @param announce_url the announcement-url
 */
void torrent_set_announce(torrent_ctx *ctx, const char* announce_url)
{
  free(ctx->announce);
  ctx->announce = rsh_strdup(announce_url);
}
示例#17
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;
}
示例#18
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);
}
示例#19
0
文件: calc_sums.c 项目: 0-wiz-0/RHash
/**
 * 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);
}
示例#20
0
/**
 * Parse config file of the program.
 *
 * @return 0 on success, -1 on fail
 */
static int read_config(void)
{
#define LINE_BUF_SIZE 2048
	char buf[LINE_BUF_SIZE];
	FILE* fd;
	parsed_option_t option;
	int res;

	/* initialize conf_opt and opt structures */
	memset(&conf_opt, 0, sizeof(opt));
	conf_opt.find_max_depth = -1;

	if(!find_conf_file()) return 0;

	fd = fopen(conf_opt.config_file, "r");
	if(!fd) return -1;

	while(fgets(buf, LINE_BUF_SIZE, fd)) {
		size_t index;
		cmdline_opt_t* t;
		char* line = str_trim(buf);
		char  *name, *value;

		if(*line == 0 || IS_COMMENT(*line)) continue;

		/* search for '=' */
		index = strcspn(line, "=");
		if(line[index] == 0) {
			log_warning(_("%s: can't parse line \"%s\"\n"), conf_opt.config_file, line);
			continue;
		}
		line[index] = 0;
		name = str_trim(line);

		for(t = cmdline_opt; t->type; t++) {
			if(strcmp(name, t->long_name) == 0) {
				break;
			}
		}

		if(!t->type) {
			log_warning(_("%s: unknown option \"%s\"\n"), conf_opt.config_file, line);
			continue;
		}

		value = str_trim(line + index + 1);

		/* process a long option */
		if(is_param_required(t->type)) {
			rsh_vector_add_ptr(opt.mem, (value = rsh_strdup(value)));;
		} else {
			/* possible boolean values for a config file variable */
			static const char* strings[] = {"1", "on", "yes", 0};
			const char** cmp;
			for(cmp = strings; *cmp && strcmp(value, *cmp); cmp++);
			if(*cmp == 0) continue;
		}

		option.name = name;
		option.parameter = value;
		option.o = t;
		apply_option(&conf_opt, &option);
	}
	res = fclose(fd);

#ifdef _WIN32
	if( (opt.flags & OPT_ENCODING) == 0 ) opt.flags |= (conf_opt.flags & OPT_ENCODING);
#endif
	return (res == 0 ? 0 : -1);
}