/** * @brief Searches for free space region starting at the end of the volume. * @param[in] jp job parameters structure. * @param[in] min_lcn minimum LCN of region. * @param[in] min_length minimum length of region, in clusters. * @param[out] max_length length of the biggest region found. * @note In case of termination request returns NULL immediately. */ winx_volume_region *find_last_free_region(udefrag_job_parameters *jp, ULONGLONG min_lcn,ULONGLONG min_length,ULONGLONG *max_length) { winx_volume_region *rgn; ULONGLONG time = winx_xtime(); if(max_length) *max_length = 0; if(jp->free_regions){ for(rgn = jp->free_regions->prev; rgn; rgn = rgn->prev){ if(jp->termination_router((void *)jp)) break; if(rgn->lcn < min_lcn) break; if(max_length){ if(rgn->length > *max_length) *max_length = rgn->length; } if(rgn->length >= min_length){ jp->p_counters.searching_time += winx_xtime() - time; return rgn; } if(rgn->prev == jp->free_regions->prev) break; } } jp->p_counters.searching_time += winx_xtime() - time; return NULL; }
/** * @brief Searches for best matching free space region. * @param[in] jp job parameters structure. * @param[in] start_lcn a point which divides disk into two parts (see below). * @param[in] min_length minimal accepted length of the region, in clusters. * @param[in] preferred_position one of the FIND_MATCHING_RGN_xxx constants: * FIND_MATCHING_RGN_FORWARD - region after the start_lcn preferred * FIND_MATCHING_RGN_BACKWARD - region before the start_lcn preferred * FIND_MATCHING_RGN_ANY - any region accepted * @note In case of termination request returns * NULL immediately. */ winx_volume_region *find_matching_free_region(udefrag_job_parameters *jp, ULONGLONG start_lcn, ULONGLONG min_length, int preferred_position) { winx_volume_region *rgn, *rgn_matching; ULONGLONG length; ULONGLONG time = winx_xtime(); rgn_matching = NULL, length = 0; for(rgn = jp->free_regions; rgn; rgn = rgn->next){ if(jp->termination_router((void *)jp)){ jp->p_counters.searching_time += winx_xtime() - time; return NULL; } if(preferred_position == FIND_MATCHING_RGN_BACKWARD \ && rgn->lcn > start_lcn) if(rgn_matching != NULL) break; if(rgn->length >= min_length){ if(length == 0 || rgn->length < length){ rgn_matching = rgn; length = rgn->length; if(length == min_length \ && preferred_position != FIND_MATCHING_RGN_FORWARD) break; } } if(rgn->next == jp->free_regions) break; } jp->p_counters.searching_time += winx_xtime() - time; return rgn_matching; }
/** * @brief Searches for well known locked files * and applies their dispositions to the map. * @details Resets f->disp structure of locked files. */ static void redraw_well_known_locked_files(udefrag_job_parameters *jp) { winx_file_info *f; ULONGLONG time; ULONGLONG n = 0; winx_dbg_print_header(0,0,I"searching for well known locked files..."); time = winx_xtime(); for(f = jp->filelist; f; f = f->next){ if(f->disp.blockmap){ /* otherwise nothing to redraw */ if(is_well_known_locked_file(f,jp)){ if(!is_file_locked(f,jp)){ /* possibility of this case should be reduced */ dtrace("file wasn't locked: %ws",f->path); } else { itrace("locked file DETECTED: %ws",f->path); n ++; } } } if(f->next == jp->filelist) break; } itrace("%I64u locked files found",n); winx_dbg_print_header(0,0,I"well known locked files search completed in %I64u ms", winx_xtime() - time); }
/** * @brief Saves fragmentation report on the volume. * @return Zero for success, negative value otherwise. */ int save_fragmentation_report(udefrag_job_parameters *jp) { int result = 0; ULONGLONG time; winx_dbg_print_header(0,0,I"*"); winx_dbg_print_header(0,0,I"report saving started"); if(jp->job_type != ANALYSIS_JOB) dbg_print_file_counters(jp); if(jp->udo.disable_reports) return 0; time = winx_xtime(); result = save_lua_report(jp); winx_dbg_print_header(0,0,I"report saved in %I64u ms", winx_xtime() - time); return result; }
/** * @brief Searches for largest free space region. * @note In case of termination request returns * NULL immediately. */ winx_volume_region *find_largest_free_region(udefrag_job_parameters *jp) { winx_volume_region *rgn, *rgn_largest; ULONGLONG length; ULONGLONG time = winx_xtime(); rgn_largest = NULL, length = 0; for(rgn = jp->free_regions; rgn; rgn = rgn->next){ if(jp->termination_router((void *)jp)){ jp->p_counters.searching_time += winx_xtime() - time; return NULL; } if(rgn->length > length){ rgn_largest = rgn; length = rgn->length; } if(rgn->next == jp->free_regions) break; } jp->p_counters.searching_time += winx_xtime() - time; return rgn_largest; }
/** * @brief Performs a volume analysis. * @return Zero for success, negative value otherwise. */ int analyze(udefrag_job_parameters *jp) { ULONGLONG time; int result; time = start_timing("analysis",jp); jp->pi.current_operation = VOLUME_ANALYSIS; /* update volume information */ result = get_volume_information(jp); if(result < 0) return result; /* scan volume for free space areas */ if(get_free_space_layout(jp) < 0) return (-1); /* redraw mft zone in light magenta */ get_mft_zones_layout(jp); /* search for files */ if(find_files(jp) < 0) return (-1); /* redraw well known locked files in green */ redraw_well_known_locked_files(jp); /* produce list of fragmented files */ produce_list_of_fragmented_files(jp); (void)check_fragmentation_level(jp); /* for debugging */ result = check_requested_action(jp); if(result < 0) return result; jp->p_counters.analysis_time = winx_xtime() - time; stop_timing("analysis",time,jp); return 0; }
/** * @brief Searches for the first movable file block * after the specified cluster on the volume. * @param[in] jp job parameters. * @param[in,out] min_lcn pointer to variable containing * minimum LCN - file blocks below it will be ignored. * @param[in] flags one of SKIP_xxx flags defined in udefrag.h * @param[out] first_file pointer to variable receiving information * about the file the first block belongs to. * @return Pointer to the first block. NULL indicates failure. */ winx_blockmap *find_first_block(udefrag_job_parameters *jp, ULONGLONG *min_lcn, int flags, winx_file_info **first_file) { winx_file_info *found_file; winx_blockmap *first_block; winx_blockmap b; struct file_block fb, *item; struct prb_traverser t; int movable_file; ULONGLONG tm = winx_xtime(); if(min_lcn == NULL || first_file == NULL) return NULL; found_file = NULL; first_block = NULL; b.lcn = *min_lcn; fb.block = &b; prb_t_init(&t,jp->file_blocks); item = prb_t_insert(&t,jp->file_blocks,&fb); if(item == &fb){ /* block at min_lcn not found */ item = prb_t_next(&t); if(prb_delete(jp->file_blocks,&fb) == NULL){ etrace("cannot remove block from the tree"); winx_flush_dbg_log(0); /* 'cause error is critical */ } } if(item){ found_file = item->file; first_block = item->block; } while(!jp->termination_router((void *)jp)){ if(found_file == NULL) break; if(flags & SKIP_PARTIALLY_MOVABLE_FILES){ movable_file = can_move_entirely(found_file,jp); } else { movable_file = can_move(found_file,jp); } if(is_file_locked(found_file,jp)) movable_file = 0; if(movable_file){ if(jp->is_fat && is_directory(found_file) && first_block == found_file->disp.blockmap){ /* skip first fragments of FAT directories */ } else { /* desired block found */ *min_lcn = first_block->lcn + 1; /* the current block will be skipped later anyway in this case */ *first_file = found_file; jp->p_counters.searching_time += winx_xtime() - tm; return first_block; } } /* skip current block */ *min_lcn = *min_lcn + 1; /* and go to the next one */ item = prb_t_next(&t); if(item == NULL) break; found_file = item->file; first_block = item->block; } *first_file = NULL; jp->p_counters.searching_time += winx_xtime() - tm; return NULL; }