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); }
/** * Fill file information in the file_t structure. * * @param file the file information * @return 0 on success, -1 on error */ int rsh_file_stat(file_t* file) { return rsh_file_stat2(file, 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.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; }