/** * 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); }
/** * Output SFV-formated file header. */ static void preprocess_files(void) { int i; /* print SFV file header */ if(opt.fmt == FMT_SFV && opt.mode == 0) { print_sfv_banner(rhash_data.out); for(i = 0; i < opt.n_files; i++) { char *path = opt.files[i]; if(opt.flags & OPT_RECURSIVE) { struct rsh_stat_struct stat_buf; if(rsh_stat(path, &stat_buf) < 0) { continue; /* don't report error here, it'll be reported later */ } /* if file is a directory, then walk it recursively */ if(S_ISDIR(stat_buf.st_mode)) { find_file(path, find_file_callback, 0, opt.find_max_depth, (void*)1); continue; } } print_sfv_header_line(rhash_data.out, path, path); } fflush(rhash_data.out); } }
/** * Search for config file. * * @return the relative path to config file */ static const char* find_conf_file(void) { # define CONF_FILE_NAME "rhashrc" struct rsh_stat_struct st; char *dir1, *path; #ifndef _WIN32 /* Linux/Unix part */ /* first check for $HOME/.rhashrc file */ if( (dir1 = getenv("HOME")) ) { path = make_path(dir1, ".rhashrc"); if(rsh_stat(path, &st) >= 0) { rsh_vector_add_ptr(opt.mem, path); return (conf_opt.config_file = path); } free(path); } /* then check for global config */ if(rsh_stat( (path = "/etc/" CONF_FILE_NAME), &st) >= 0) { return (conf_opt.config_file = path); } #else /* _WIN32 */ /* first check for the %APPDATA%\RHash\rhashrc config */ if( (dir1 = getenv("APPDATA")) ) { dir1 = make_path(dir1, "RHash"); rsh_vector_add_ptr(opt.mem, path = make_path(dir1, CONF_FILE_NAME)); free(dir1); if(rsh_stat(path, &st) >= 0) { return (conf_opt.config_file = path); } } /* then check for %HOMEDRIVE%%HOMEPATH%\rhashrc */ /* note that %USERPROFILE% is generally not a user home dir */ if( (dir1 = getenv("HOMEDRIVE")) && (path = getenv("HOMEPATH"))) { dir1 = make_path(dir1, path); rsh_vector_add_ptr(opt.mem, path = make_path(dir1, CONF_FILE_NAME)); free(dir1); if(rsh_stat(path, &st) >= 0) { return (conf_opt.config_file = path); } } #endif /* _WIN32 */ return (conf_opt.config_file = NULL); /* config file not found */ }
/** * 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; }
/** * 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); } }
/** * Fill file information in the file_t structure. * * @param file the file information * @param use_lstat nonzero if lstat() shall be used * @return 0 on success, -1 on error */ int rsh_file_stat2(file_t* file, int use_lstat) { struct rsh_stat_struct st; int res = -1; #ifdef _WIN32 int i; (void)use_lstat; /* ignore on windows */ if(file->wpath) { free(file->wpath); file->wpath = NULL; } for(i = 0; i < 2; i++) { wchar_t* wpath = c2w(file->path, i); if(wpath == NULL) continue; res = clib_wstat(wpath, &st); if(res == 0 || errno != ENOENT) { file->wpath = wpath; file->size = st.st_size; /* set correct filesize for large files under win32 */ win32_set_filesize64(file->path, &file->size); break; } free(wpath); } #else res = (use_lstat ? lstat(file->path, &st) : rsh_stat(file->path, &st)); file->size = st.st_size; #endif /* _WIN32 */ file->mtime = st.st_mtime; return res; }