/* Checks that the current item at |trav| is |i| and that its previous and next items are as they should be. |label| is a name for the traverser used in reporting messages. There should be |n| items in the tree numbered |0|@dots{}|n - 1|. Returns nonzero only if there is an error. */ static int check_traverser (struct prb_traverser *trav, int i, int n, const char *label) { int okay = 1; int *cur, *prev, *next; prev = prb_t_prev (trav); if ((i == 0 && prev != NULL) || (i > 0 && (prev == NULL || *prev != i - 1))) { printf (" %s traverser ahead of %d, but should be ahead of %d.\n", label, prev != NULL ? *prev : -1, i == 0 ? -1 : i - 1); okay = 0; } prb_t_next (trav); cur = prb_t_cur (trav); if (cur == NULL || *cur != i) { printf (" %s traverser at %d, but should be at %d.\n", label, cur != NULL ? *cur : -1, i); okay = 0; } next = prb_t_next (trav); if ((i == n - 1 && next != NULL) || (i != n - 1 && (next == NULL || *next != i + 1))) { printf (" %s traverser behind %d, but should be behind %d.\n", label, next != NULL ? *next : -1, i == n - 1 ? -1 : i + 1); okay = 0; } prb_t_prev (trav); return okay; }
static int save_lua_report(udefrag_job_parameters *jp) { wchar_t *path = NULL; WINX_FILE *f; wchar_t *cn; wchar_t compname[MAX_COMPUTERNAME_LENGTH + 1]; char utf8_compname[(MAX_COMPUTERNAME_LENGTH + 1) * 4]; char buffer[512]; struct prb_traverser t; winx_file_info *file; char *comment; char *status; int length; winx_time tm; /* should be enough for any path in UTF-8 encoding */ #define MAX_UTF8_PATH_LENGTH (256 * 1024) char *utf8_path; utf8_path = winx_tmalloc(MAX_UTF8_PATH_LENGTH); if(utf8_path == NULL){ mtrace(); return (-1); } path = get_report_path(jp); if(path == NULL) return UDEFRAG_NO_MEM; f = winx_fbopen(path,"w",RSB_SIZE); if(f == NULL){ f = winx_fopen(path,"w"); if(f == NULL){ winx_free(path); winx_free(utf8_path); return (-1); } } /* print header */ cn = winx_getenv(L"COMPUTERNAME"); if(cn){ wcsncpy(compname,cn,MAX_COMPUTERNAME_LENGTH + 1); compname[MAX_COMPUTERNAME_LENGTH] = 0; winx_free(cn); } else { wcscpy(compname,L"nil"); } winx_to_utf8(utf8_compname,sizeof(utf8_compname),compname); memset(&tm,0,sizeof(winx_time)); (void)winx_get_local_time(&tm); (void)_snprintf(buffer,sizeof(buffer), "-- UltraDefrag report for disk %c:\r\n\r\n" "format_version = 7\r\n\r\n" "volume_letter = \"%c\"\r\n" "computer_name = \"%hs\"\r\n\r\n" "current_time = {\r\n" "\tyear = %04i,\r\n" "\tmonth = %02i,\r\n" "\tday = %02i,\r\n" "\thour = %02i,\r\n" "\tmin = %02i,\r\n" "\tsec = %02i,\r\n" "\tisdst = false\r\n" "}\r\n\r\n" "files = {\r\n", jp->volume_letter, jp->volume_letter,utf8_compname, (int)tm.year,(int)tm.month,(int)tm.day, (int)tm.hour,(int)tm.minute,(int)tm.second ); buffer[sizeof(buffer) - 1] = 0; (void)winx_fwrite(buffer,1,strlen(buffer),f); /* print body */ prb_t_init(&t,jp->fragmented_files); file = prb_t_first(&t,jp->fragmented_files); while(file){ if(is_directory(file)) comment = "[DIR]"; else if(is_compressed(file)) comment = "[CMP]"; else comment = " - "; /* * On change of status strings don't forget * also to adjust write_file_status routine * in udreportcnv.lua file. */ if(is_locked(file)) status = "locked"; else if(is_moving_failed(file)) status = "move failed"; else if(is_in_improper_state(file)) status = "invalid"; else status = " - "; (void)_snprintf(buffer, sizeof(buffer), "\t{fragments = %u," "size = %I64u," "comment = \"%s\"," "status = \"%s\"," "path = \"", (UINT)file->disp.fragments, file->disp.clusters * jp->v_info.bytes_per_cluster, comment, status ); buffer[sizeof(buffer) - 1] = 0; (void)winx_fwrite(buffer,1,strlen(buffer),f); if(file->path != NULL){ /* skip \??\ sequence in the beginning of the path */ length = (int)wcslen(file->path); if(length > 4){ convert_to_utf8_path(utf8_path,MAX_UTF8_PATH_LENGTH,file->path + 4); } else { convert_to_utf8_path(utf8_path,MAX_UTF8_PATH_LENGTH,file->path); } (void)winx_fwrite(utf8_path,1,strlen(utf8_path),f); } (void)strcpy(buffer,"\"},\r\n"); (void)winx_fwrite(buffer,1,strlen(buffer),f); file = prb_t_next(&t); } /* print footer */ (void)strcpy(buffer,"}\r\n"); (void)winx_fwrite(buffer,1,strlen(buffer),f); itrace("report saved to %ws",path); winx_fclose(f); winx_free(path); winx_free(utf8_path); return 0; }
/* Checks that |tree| is well-formed and verifies that the values in |array[]| are actually in |tree|. There must be |n| elements in |array[]| and |tree|. Returns nonzero only if no errors detected. */ static int verify_tree (struct prb_table *tree, int array[], size_t n) { int okay = 1; /* Check |tree|'s bst_count against that supplied. */ if (prb_count (tree) != n) { printf (" Tree count is %lu, but should be %lu.\n", (unsigned long) prb_count (tree), (unsigned long) n); okay = 0; } if (okay) { if (tree->prb_root != NULL && tree->prb_root->prb_color != PRB_BLACK) { printf (" Tree's root is not black.\n"); okay = 0; } } if (okay) { /* Recursively verify tree structure. */ size_t count; int bh; recurse_verify_tree (tree->prb_root, &okay, &count, 0, INT_MAX, &bh); if (count != n) { printf (" Tree has %lu nodes, but should have %lu.\n", (unsigned long) count, (unsigned long) n); okay = 0; } } if (okay) { /* Check that all the values in |array[]| are in |tree|. */ size_t i; for (i = 0; i < n; i++) if (prb_find (tree, &array[i]) == NULL) { printf (" Tree does not contain expected value %d.\n", array[i]); okay = 0; } } if (okay) { /* Check that |prb_t_first()| and |prb_t_next()| work properly. */ struct prb_traverser trav; size_t i; int prev = -1; int *item; for (i = 0, item = prb_t_first (&trav, tree); i < 2 * n && item != NULL; i++, item = prb_t_next (&trav)) { if (*item <= prev) { printf (" Tree out of order: %d follows %d in traversal\n", *item, prev); okay = 0; } prev = *item; } if (i != n) { printf (" Tree should have %lu items, but has %lu in traversal\n", (unsigned long) n, (unsigned long) i); okay = 0; } } if (okay) { /* Check that |prb_t_last()| and |prb_t_prev()| work properly. */ struct prb_traverser trav; size_t i; int next = INT_MAX; int *item; for (i = 0, item = prb_t_last (&trav, tree); i < 2 * n && item != NULL; i++, item = prb_t_prev (&trav)) { if (*item >= next) { printf (" Tree out of order: %d precedes %d in traversal\n", *item, next); okay = 0; } next = *item; } if (i != n) { printf (" Tree should have %lu items, but has %lu in reverse\n", (unsigned long) n, (unsigned long) i); okay = 0; } } if (okay) { /* Check that |prb_t_init()| works properly. */ struct prb_traverser init, first, last; int *cur, *prev, *next; prb_t_init (&init, tree); prb_t_first (&first, tree); prb_t_last (&last, tree); cur = prb_t_cur (&init); if (cur != NULL) { printf (" Inited traverser should be null, but is actually %d.\n", *cur); okay = 0; } next = prb_t_next (&init); if (next != prb_t_cur (&first)) { printf (" Next after null should be %d, but is actually %d.\n", *(int *) prb_t_cur (&first), *next); okay = 0; } prb_t_prev (&init); prev = prb_t_prev (&init); if (prev != prb_t_cur (&last)) { printf (" Previous before null should be %d, but is actually %d.\n", *(int *) prb_t_cur (&last), *prev); okay = 0; } prb_t_next (&init); } return okay; }
/** * @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; }