/** * 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); } }
/** * Callback function to process a file found while recursively traversing * a directory. * * @param filepath path to the file * @param type file attributes * @param data the paramater specified, when calling find_file(). It shall be * non-zero for printing SFV header, zero for actual processing. */ static int find_file_callback(const char* filepath, int type, void* data) { int res = 0; if( !(type & FIND_IFDIR) ) { if(data) { if(!file_mask_match(opt.files_accept, filepath)) return 0; if(filepath[0] == '.' && IS_PATH_SEPARATOR(filepath[1])) filepath += 2; /* TODO: get size, fill file struct */ print_sfv_header_line(rhash_data.out, filepath, filepath); /* rhash_data.total_size += file.size */ } else { /* only check an update modes use crc_accept mask */ file_mask_array* masks = (opt.mode & (MODE_CHECK | MODE_UPDATE) ? opt.crc_accept : opt.files_accept); if(!file_mask_match(masks, filepath)) return 0; if(opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) { res = check_hash_file(filepath, 1); } else { if(opt.mode & MODE_UPDATE) { res = update_hash_file(filepath); } else { /* default mode: calculate hash */ if(filepath[0] == '.' && IS_PATH_SEPARATOR(filepath[1])) filepath += 2; res = calculate_and_print_sums(rhash_data.out, filepath, filepath, NULL); rhash_data.processed++; } } } } if(res < 0) rhash_data.error_flag = 1; return 1; }
/** * Callback function to process files while recursively traversing a directory. * It hashes, checks or updates a file according to the current work mode. * * @param file the file to process * @param preprocess non-zero when preprocessing files, zero for actual processing. */ static int find_file_callback(file_t* file, int preprocess) { int res = 0; assert(!FILE_ISDIR(file)); assert(opt.search_data); if (rhash_data.interrupted) { opt.search_data->options |= FIND_CANCEL; return 0; } if (preprocess) { if (!file_mask_match(opt.files_accept, file->path) || must_skip_file(file)) { return 0; } if (opt.fmt & FMT_SFV) { print_sfv_header_line(rhash_data.out, file, 0); } rhash_data.batch_size += file->size; } else { int not_root = !(file->mode & FILE_IFROOT); if (not_root) { /* only check and update modes use the crc_accept mask */ file_mask_array* masks = (opt.mode & (MODE_CHECK | MODE_UPDATE) ? opt.crc_accept : opt.files_accept); if (!file_mask_match(masks, file->path)) return 0; } if (must_skip_file(file)) return 0; if (opt.mode & (MODE_CHECK | MODE_CHECK_EMBEDDED)) { res = check_hash_file(file, not_root); } else { if (opt.mode & MODE_UPDATE) { res = update_hash_file(file); } else { /* default mode: calculate hash */ const char* print_path = file->path; if (print_path[0] == '.' && IS_PATH_SEPARATOR(print_path[1])) print_path += 2; res = calculate_and_print_sums(rhash_data.out, file, print_path); if (rhash_data.interrupted) return 0; rhash_data.processed++; } } } if (res < 0) rhash_data.error_flag = 1; return 1; }
/** * 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; }