/** * Load printf-template from file, specified by options or config. */ static int load_printf_template(void) { FILE* fd = fopen(opt.template_file, "rb"); char buffer[8192]; size_t len; int error = 0; if(!fd) { log_file_error(opt.template_file); return 0; } rhash_data.template_text = rsh_str_new(); while(!feof(fd)) { len = fread(buffer, 1, 8192, fd); /* read can return -1 on error */ if(len == (size_t)-1) break; rsh_str_append_n(rhash_data.template_text, buffer, len); if(rhash_data.template_text->len >= MAX_TEMPLATE_SIZE) { log_msg(_("%s: template file is too big\n"), opt.template_file); error = 1; } } if(ferror(fd)) { log_file_error(opt.template_file); error = 1; } fclose(fd); rhash_data.printf_str = rhash_data.template_text->str; return !error; }
/** * 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); }
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); }
void scan_files(file_search_data* data) { size_t i; size_t count = data->root_files.size; int skip_symlink_dirs = !(data->options & FIND_FOLLOW_SYMLINKS); for (i = 0; i < count && !(data->options & FIND_CANCEL); i++) { file_t* file = get_root_file(data, i); assert(!!(file->mode & FILE_IFROOT)); /* check if file is a directory */ if (FILE_ISDIR(file)) { /* silently skip symlinks to directories if required */ if (skip_symlink_dirs && FILE_ISLNK(file)) { continue; } if (data->max_depth != 0) { dir_scan(file, data); } else if ((data->options & FIND_LOG_ERRORS) != 0) { errno = EISDIR; log_file_error(file->path); } } else { /* process a regular file or a dash '-' path */ data->call_back(file, data->call_back_data); } } }
/* Load configfile from directories */ int load_user_config(t_session *session) { char *search, *conffile; int length, result; if (session->file_on_disk == NULL) { return 0; } search = session->file_on_disk; while (*search != '\0') { if (*search == '/') { length = search - session->file_on_disk + 1; if ((conffile = (char*)malloc(length + 10)) == NULL) { return -1; } else { memcpy(conffile, session->file_on_disk, length); memcpy(conffile + length, ".hiawatha\0", 10); result = read_user_configfile(conffile, session->host, &(session->tempdata)); if (result != 0) { log_file_error(session, conffile, "error in configuration file on line %d", result); free(conffile); return -1; } free(conffile); } } search++; } return 0; }
static void setup_log_stream(FILE **p_stream, const opt_tchar* stream_path) { if (stream_path && !(*p_stream = rsh_tfopen(stream_path, RSH_T("w"))) ) { log_file_error(t2c(stream_path)); rsh_exit(2); } }
/** * 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); } }
/* Load configfile from directories */ int load_user_config(t_session *session) { char *search, *conffile; size_t length; int result; t_user_config_mode read_mode; if (session->file_on_disk == NULL) { return 0; } else if ((length = strlen(session->file_on_disk)) <= 1) { return 0; } else if ((conffile = (char*)malloc(length + 10)) == NULL) { return -1; } search = session->file_on_disk + 1; while (*search != '\0') { if (*search == '/') { length = search - session->file_on_disk + 1; if (length - 1 != session->host->website_root_len) { read_mode = non_root_config; } else if (memcmp(session->file_on_disk, session->host->website_root, length - 1) != 0) { read_mode = non_root_config; } else { read_mode = ignore_root_config; } memcpy(conffile, session->file_on_disk, length); memcpy(conffile + length, ".hiawatha\0", 10); result = read_user_configfile(conffile, session->host, &(session->tempdata), read_mode); if (result != 0) { log_file_error(session, conffile, "error in configuration file on line %d", result); free(conffile); return -1; } } search++; } free(conffile); return 0; }
int load_user_root_config(t_session *session) { char *conffile; int result; if ((conffile = malloc(session->host->website_root_len + 11)) == NULL) { return -1; } memcpy(conffile, session->host->website_root, session->host->website_root_len); memcpy(conffile + session->host->website_root_len, "/.hiawatha\0", 11); if ((result = read_user_configfile(conffile, session->host, &(session->tempdata), only_root_config)) != 0) { log_file_error(session, conffile, "error in configuration file on line %d", result); result = -1; } free(conffile); return result; }
/* Run a program */ static int run_program(t_session *session, char *program, int return_code) { pid_t pid; char ip[MAX_IP_STR_LEN], value[10], *pos, slash = '/'; switch (pid = fork()) { case -1: log_file_error(session, program, "fork() error"); return -1; case 0: if (setsid() == -1) { log_file_error(session, program, "setsid() error"); } else { /* Close all other open filedescriptors. */ close_bindings(session->config->binding); close_client_sockets_for_cgi_run(); close_logfiles_for_cgi_run(session->config->first_host); /* Set environment variables */ setenv("REQUEST_METHOD", session->method, 1); setenv("DOCUMENT_ROOT", session->host->website_root, 1); setenv("REQUEST_URI", session->request_uri, 1); if (session->remote_user != NULL) { setenv("REMOTE_USER", session->remote_user, 1); } if (inet_ntop(session->ip_address.family, &(session->ip_address.value), ip, MAX_IP_STR_LEN) != NULL) { setenv("REMOTE_ADDR", ip, 1); } snprintf(value, 9, "%d", return_code); setenv("HTTP_RETURN_CODE", value, 1); http_header_to_environment(session, NULL, "Range:", "HTTP_RANGE"); http_header_to_environment(session, NULL, "Referer:", "HTTP_REFERER"); http_header_to_environment(session, NULL, "User-Agent:", "HTTP_USER_AGENT"); /* Change directory to program's directory */ pos = strrchr(program, slash); #ifdef CYGWIN if ((pos == NULL) && (session->config->platform == windows)) { slash = '\\'; pos = strrchr(program, slash); } #endif if (pos != NULL) { *pos = '\0'; if (chdir(program) == -1) { exit(EXIT_FAILURE); } *pos = slash; } /* Execute program */ execlp(program, program, (char*)NULL); log_file_error(session, program, "exec() error"); } exit(EXIT_FAILURE); default: if (session->config->wait_for_cgi) { waitpid(pid, NULL, 0); } } return 0; }
/* Handle an HTTP error. */ static int handle_error(t_session *session, int error_code) { t_error_handler *error_handler; char *new_fod; int result = -1; #ifdef ENABLE_XSLT char *xslt_file; #endif error_handler = session->host->error_handlers; while (error_handler != NULL) { if (error_handler->code == error_code) { break; } error_handler = error_handler->next; } if (error_handler == NULL) { return 0; } session->return_code = error_code; session->error_code = error_code; session->handling_error = true; session->mimetype = NULL; session->vars = error_handler->parameters; if ((new_fod = (char*)malloc(session->host->website_root_len + strlen(error_handler->handler) + 4)) == NULL) { /* + 3 for .gz (gzip encoding) */ log_error(session, "malloc() error while handling error"); return 500; } if (session->file_on_disk != NULL) { free(session->file_on_disk); } session->file_on_disk = new_fod; memcpy(session->file_on_disk, session->host->website_root, session->host->website_root_len); strcpy(session->file_on_disk + session->host->website_root_len, error_handler->handler); if (get_target_extension(session) == -1) { log_error(session, "error getting extension while handing error"); return 500; } check_target_is_cgi(session); if (session->cgi_type != no_cgi) { result = execute_cgi(session); #ifdef ENABLE_XSLT } else if ((xslt_file = find_xslt_file(session)) != NULL) { result = handle_xml_file(session, xslt_file); free(xslt_file); #endif } else switch (is_directory(session->file_on_disk)) { case error: result = 500; break; case yes: result = 301; break; case no: result = send_file(session); break; case no_access: result = 403; break; case not_found: result = 404; break; } switch (result) { case 301: log_error(session, "ErrorHandler is a directory"); break; case 403: log_error(session, "no access to ErrorHandler"); break; case 404: log_error(session, "ErrorHandler not found"); break; case 500: log_file_error(session, error_handler->handler, "internal error for ErrorHandler"); session->keep_alive = false; break; case 503: log_file_error(session, error_handler->handler, "FastCGI for ErrorHandler not available"); break; } return result; }
/** * Print file error to the program log. * * @param file the file, caused the error */ void log_file_t_error(struct file_t* file) { log_file_error(file_cpath(file)); }
/* 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }
/* Log an error */ void log_error(t_session *session, char *mesg) { log_file_error(session, session->file_on_disk, mesg); }