Пример #1
0
/**
 * @internal
 * @brief Retrieves the volume label.
 * @param[in] hRoot handle to the
 * root directory.
 * @param[out] pointer to the structure
 * receiving the volume label.
 */
static void get_volume_label(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_VOLUME_INFORMATION *ffvi;
    int buffer_size;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    
    /* reset label */
    v->label[0] = 0;
    
    /* allocate memory */
    buffer_size = (sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(wchar_t)) + (MAX_PATH + 1) * sizeof(wchar_t);
    ffvi = winx_malloc(buffer_size);
    
    /* try to get actual label */
    RtlZeroMemory(ffvi,buffer_size);
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,ffvi,
                buffer_size,FileFsVolumeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get volume label of drive %c:",
            v->volume_letter);
        winx_free(ffvi);
        return;
    }
    wcsncpy(v->label,ffvi->VolumeLabel,MAX_PATH);
    v->label[MAX_PATH] = 0;
    winx_free(ffvi);
}
Пример #2
0
/**
 * @brief Removes an item from a double linked list.
 * @details Frees memory allocated for the item to be removed.
 * @param[in,out] phead pointer to a variable pointing to the list head.
 * @param[in] item pointer to the item which must be removed.
 */
void winx_list_remove(list_entry **phead,list_entry *item)
{
    /*
    * Avoid winx_dbg_xxx calls here
    * to avoid recursion.
    */

    /* validate the item */
    if(item == NULL) return;
    
    /* is list empty? */
    if(*phead == NULL) return;

    /* remove alone first item? */
    if(item == *phead && item->next == *phead){
        winx_free(item);
        *phead = NULL;
        return;
    }
    
    /* remove first item? */
    if(item == *phead){
        *phead = (*phead)->next;
    }
    item->prev->next = item->next;
    item->next->prev = item->prev;
    winx_free(item);
}
Пример #3
0
/**
 * @brief Queries an environment variable.
 * @param[in] name the environment variable name.
 * @return The value of the environment variable.
 * NULL indicates failure.
 * @note The returned string should be freed
 * by the winx_free call after its use.
 */
wchar_t *winx_getenv(wchar_t *name)
{
    wchar_t *value;
    UNICODE_STRING n, v;
    NTSTATUS status;
    
    DbgCheck1(name,NULL);
    
    value = winx_malloc(MAX_ENV_VALUE_LENGTH * sizeof(wchar_t));

    RtlInitUnicodeString(&n,name);
    v.Buffer = value;
    v.Length = 0;
    v.MaximumLength = MAX_ENV_VALUE_LENGTH * sizeof(wchar_t);
    status = RtlQueryEnvironmentVariable_U(NULL,&n,&v);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot query %ws",name);
        winx_free(value);
        return NULL;
    }
    if(value[0] == 0){
        winx_free(value);
        return NULL;
    }
    return value;
}
Пример #4
0
/**
 * @internal
 * @brief Saves the list of boot
 * execute programs to registry.
 * @return Zero for success,
 * negative value otherwise.
 */
static int save_boot_exec_list(struct cmd *list)
{
    struct cmd *c;
    int length = 1;
    wchar_t *commands, *p;
    NTSTATUS status;
    
    for(c = list; c; c = c->next){
        if(c->cmd[0]) length += (int)wcslen(c->cmd) + 1;
        if(c->next == list) break;
    }
    commands = winx_malloc(length * sizeof(wchar_t));
    memset(commands,0,length * sizeof(wchar_t));
    for(c = list, p = commands; c; c = c->next){
        if(c->cmd[0]){
            wcscpy(p,c->cmd);
            p += wcslen(c->cmd) + 1;
        }
        if(c->next == list) break;
    }
    
    status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL,
        L"Session Manager",L"BootExecute",REG_MULTI_SZ,
        commands,length * sizeof(wchar_t));
    winx_free(commands);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot save list of boot execute commands");
        return (-1);
    }
    return 0;
}
Пример #5
0
/**
 * @brief Removes a file block from
 * the binary tree of all file blocks.
 * @return Zero for success, 
 * negative value otherwise.
 */
int remove_block_from_file_blocks_tree(udefrag_job_parameters *jp, winx_blockmap *block)
{
    struct file_block *fb;
    struct file_block b;
    
    if(block == NULL)
        return (-1);
    
    if(jp->file_blocks == NULL)
        return (-1);

    b.file = NULL;
    b.block = block;
    fb = prb_delete(jp->file_blocks,&b);
    if(fb == NULL){
        /* the following debugging output indicates either
           a bug, or file system inconsistency */
        etrace("failed for %p: VCN = %I64u, LCN = %I64u, LEN = %I64u",
            block, block->vcn, block->lcn, block->length);
        /* if block does not exist in tree, we have nothing to cleanup */
        return 0;
    }
    winx_free(fb);
    return 0;
}
Пример #6
0
static wchar_t *get_report_path(udefrag_job_parameters *jp)
{
    wchar_t *instdir, *fpath;
    wchar_t *isportable;//genBTC
    wchar_t *path = NULL;

    isportable = winx_getenv(L"UD_IS_PORTABLE");//genBTC
    if(isportable != NULL){
        /* portable version? */
        fpath = winx_get_module_filename();
        if(fpath == NULL){
            etrace("cannot get program\'s path");
        } else {
            winx_path_remove_filename(fpath);
            path = winx_swprintf(L"\\??\\%ws\\reports",fpath);
            if(path == NULL){
                etrace("not enough memory (case 1)");
            } else {
                (void)winx_create_directory(path);
                winx_free(path);
            }
            path = winx_swprintf(L"\\??\\%ws\\reports\\fraglist_%c.luar",
                fpath,winx_tolower(jp->volume_letter));
            if(path == NULL)
                etrace("not enough memory (case 2)");
            winx_free(fpath);
        }
    } else {
        instdir = winx_getenv(L"UD_INSTALL_DIR");
        /* regular installation */
        path = winx_swprintf(L"\\??\\%ws\\reports",instdir);
        if(path == NULL){
            etrace("not enough memory (case 3)");
        } else {
            (void)winx_create_directory(path);
            winx_free(path);
        }
        path = winx_swprintf(L"\\??\\%ws\\reports\\fraglist_%c.luar",
            instdir,winx_tolower(jp->volume_letter));
        if(path == NULL)
            etrace("not enough memory (case 4)");
        winx_free(instdir);
    }
    return path;
}
Пример #7
0
/**
 * @brief Removes all fragmentation reports from the volume.
 */
void remove_fragmentation_report(udefrag_job_parameters *jp)
{
    wchar_t *paths[] = {
        L"\\??\\%c:\\fraglist.luar",
        L"\\??\\%c:\\fraglist.txt",
        L"\\??\\%c:\\fraglist.htm",
        L"\\??\\%c:\\fraglist.html",
        NULL
    };
    wchar_t path[MAX_PATH + 1];
    wchar_t *new_path, *ext_path;
    int i;
    
    winx_dbg_print_header(0,0,I"*");
    
    /* remove old reports from the root directory */
    for(i = 0; paths[i]; i++){
        _snwprintf(path,MAX_PATH,paths[i],jp->volume_letter);
        path[MAX_PATH] = 0;
        (void)winx_delete_file(path);
    }
    
    /* remove reports from the reports directory */
    new_path = get_report_path(jp);
    if(new_path){
        (void)winx_delete_file(new_path);
        winx_path_remove_extension(new_path);
        ext_path = winx_swprintf(L"%ws.txt",new_path);
        if(ext_path == NULL){
            mtrace();
        } else {
            (void)winx_delete_file(ext_path);
            winx_free(ext_path);
        }
        ext_path = winx_swprintf(L"%ws.html",new_path);
        if(ext_path == NULL){
            mtrace();
        } else {
            (void)winx_delete_file(ext_path);
            winx_free(ext_path);
        }
        winx_free(new_path);
    }
}
Пример #8
0
/**
 * @internal
 * @brief Destroys list of
 * boot execute programs.
 */
static void destroy_boot_exec_list(struct cmd *list)
{
    struct cmd *c;
    
    for(c = list; c; c = c->next){
        winx_free(c->cmd);
        if(c->next == list) break;
    }
    winx_list_destroy((list_entry **)(void *)&list);
}
Пример #9
0
/**
 * @internal
 * @brief Retrieves the name of the file system.
 * @param[in] hRoot handle to the root directory.
 * @param[out] pointer to the structure receiving
 * the filesystem name.
 * @return Zero for success, negative value otherwise.
 * @note We could analyze the first sector of the 
 * partition directly, but this method is not so swift
 * as it accesses the disk physically.
 */
static int get_filesystem_name(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_ATTRIBUTE_INFORMATION *pfa;
    int fs_attr_info_size;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    wchar_t fs_name[MAX_FS_NAME_LENGTH + 1];
    int length;

    fs_attr_info_size = MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
    pfa = winx_malloc(fs_attr_info_size);
    
    RtlZeroMemory(pfa,fs_attr_info_size);
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,pfa,
                fs_attr_info_size,FileFsAttributeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get file system name of drive %c:",v->volume_letter);
        winx_free(pfa);
        return (-1);
    }
    
    /*
    * pfa->FileSystemName.Buffer may be not NULL terminated
    * (theoretically), so name extraction is more tricky
    * than it should be.
    */
    length = min(MAX_FS_NAME_LENGTH,pfa->FileSystemNameLength / sizeof(wchar_t));
    wcsncpy(fs_name,pfa->FileSystemName,length);
    fs_name[length] = 0;
    _snprintf(v->fs_name,MAX_FS_NAME_LENGTH,"%ws",fs_name);
    v->fs_name[MAX_FS_NAME_LENGTH] = 0;

    /* cleanup */
    winx_free(pfa);
    return 0;
}
Пример #10
0
/**
 * @brief Destroys a double linked list.
 * @details Frees memory allocated for all list items.
 * @param[in,out] phead pointer to a variable
 * pointing to the list head.
 */
void winx_list_destroy(list_entry **phead)
{
    list_entry *item, *next, *head;
    
    /* is list empty? */
    if(*phead == NULL) return;

    head = *phead;
    item = head;

    do {
        next = item->next;
        winx_free(item);
        item = next;
    } while (next != head);

    *phead = NULL;
}
Пример #11
0
/**
 * @internal
 * @brief Compares two boot execute commands.
 * @details Treats 'command' and 'autocheck command' as the same.
 * @param[in] reg_cmd the command read from the registry.
 * @param[in] cmd the command to be searched for.
 * @return Positive value indicates that the commands are equal,
 * zero indicates that they're different, negative value
 * indicates a failure of the comparison.
 */
static int cmd_compare(wchar_t *reg_cmd,const wchar_t *cmd)
{
    wchar_t *long_cmd;
    int result;
    
    /* do we have the command registered as it is? */
    if(!winx_wcsicmp(cmd,reg_cmd))
        return 1;
        
    /* compare reg_cmd with 'autocheck {cmd}' */
    long_cmd = winx_swprintf(L"autocheck %ws",cmd);
    if(long_cmd == NULL){
        mtrace();
        return (-1);
    }
        
    result = winx_wcsicmp(long_cmd,reg_cmd);
    winx_free(long_cmd);
    return (result == 0) ? 1 : 0;
}
Пример #12
0
/**
 * @brief Adds a file block to
 * the binary tree of all file blocks.
 * @return Zero for success, 
 * negative value otherwise.
 * @note Destroys the tree in case of errors.
 */
int add_block_to_file_blocks_tree(udefrag_job_parameters *jp, winx_file_info *file, winx_blockmap *block)
{
    struct file_block *fb;
    void **p;
    
    if(file == NULL || block == NULL)
        return (-1);
    
    if(jp->file_blocks == NULL)
        return (-1);

    fb = winx_malloc(sizeof *fb);
    fb->file = file;
    fb->block = block;
    p = prb_probe(jp->file_blocks,(void *)fb);
    /* if a duplicate item exists... */
    if(*p != fb){
        etrace("a duplicate found");
        winx_free(fb);
    }
    return 0;
}
Пример #13
0
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;
}
Пример #14
0
/**
 * @brief Retrieves the list of free regions on the volume.
 * @param[in] volume_letter the volume letter.
 * @param[in] flags the combination of WINX_GVR_xxx flags.
 * @param[in] cb the address of the procedure to be called
 * each time when the free region is found on the volume.
 * If the callback procedure returns nonzero value,
 * the scan terminates immediately.
 * @param[in] user_defined_data pointer to the data
 * passed to the registered callback.
 * @return List of the free regions, NULL indicates that
 * either disk is full (unlikely) or some error occured.
 * @note
 * - It is possible to scan disk partially by
 * requesting the scan termination through the callback
 * procedure.
 * - The callback procedure should complete as quickly
 * as possible to avoid slowdown of the scan.
 */
winx_volume_region *winx_get_free_volume_regions(char volume_letter,
        int flags, volume_region_callback cb, void *user_defined_data)
{
    winx_volume_region *rlist = NULL, *rgn = NULL;
    BITMAP_DESCRIPTOR *bitmap;
    #define LLINVALID   ((ULONGLONG) -1)
    #define BITMAPBYTES 4096
    #define BITMAPSIZE  (BITMAPBYTES + 2 * sizeof(ULONGLONG))
    /* bit shifting array for efficient processing of the bitmap */
    unsigned char bitshift[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
    WINX_FILE *f;
    ULONGLONG i, start, next, free_rgn_start;
    IO_STATUS_BLOCK iosb;
    NTSTATUS status;
    
    /* ensure that it will work on w2k */
    volume_letter = winx_toupper(volume_letter);
    
    /* allocate memory */
    bitmap = winx_malloc(BITMAPSIZE);
    
    /* open volume */
    f = winx_vopen(volume_letter);
    if(f == NULL){
        winx_free(bitmap);
        return NULL;
    }
    
    /* get volume bitmap */
    next = 0, free_rgn_start = LLINVALID;
    do {
        /* get next portion of the bitmap */
        memset(bitmap,0,BITMAPSIZE);
        status = NtFsControlFile(winx_fileno(f),NULL,NULL,0,&iosb,
            FSCTL_GET_VOLUME_BITMAP,&next,sizeof(ULONGLONG),
            bitmap,BITMAPSIZE);
        if(NT_SUCCESS(status)){
            NtWaitForSingleObject(winx_fileno(f),FALSE,NULL);
            status = iosb.Status;
        }
        if(status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW){
            strace(status,"cannot get volume bitmap");
            winx_fclose(f);
            winx_free(bitmap);
            if(flags & WINX_GVR_ALLOW_PARTIAL_SCAN){
                return rlist;
            } else {
                winx_list_destroy((list_entry **)(void *)&rlist);
                return NULL;
            }
        }
        
        /* scan through the returned bitmap info */
        start = bitmap->StartLcn;
        for(i = 0; i < min(bitmap->ClustersToEndOfVol, 8 * BITMAPBYTES); i++){
            if(!(bitmap->Map[ i/8 ] & bitshift[ i % 8 ])){
                /* cluster is free */
                if(free_rgn_start == LLINVALID)
                    free_rgn_start = start + i;
            } else {
                /* cluster isn't free */
                if(free_rgn_start != LLINVALID){
                    /* add free region to the list */
                    rgn = (winx_volume_region *)winx_list_insert((list_entry **)(void *)&rlist,
                        (list_entry *)rgn,sizeof(winx_volume_region));
                    rgn->lcn = free_rgn_start;
                    rgn->length = start + i - free_rgn_start;
                    if(cb != NULL){
                        if(cb(rgn,user_defined_data))
                            goto done;
                    }
                    free_rgn_start = LLINVALID;
                }
            }
        }
        
        /* go to the next portion of data */
        next = bitmap->StartLcn + i;
    } while(status != STATUS_SUCCESS);

    if(free_rgn_start != LLINVALID){
        /* add free region to the list */
        rgn = (winx_volume_region *)winx_list_insert((list_entry **)(void *)&rlist,
            (list_entry *)rgn,sizeof(winx_volume_region));
        rgn->lcn = free_rgn_start;
        rgn->length = start + i - free_rgn_start;
        if(cb != NULL){
            if(cb(rgn,user_defined_data))
                goto done;
        }
        free_rgn_start = LLINVALID;
    }

done:    
    /* cleanup */
    winx_fclose(f);
    winx_free(bitmap);
    return rlist;
}
Пример #15
0
/**
 * @brief Auxiliary routine used to free memory allocated for tree items.
 */
static void free_item (void *prb_item, void *prb_param)
{
    struct file_block *item = (struct file_block *)prb_item;
    winx_free(item);
}