Example #1
0
/**
 * @brief fflush equivalent for entire volume.
 */
int winx_vflush(char volume_letter)
{
    wchar_t path[] = L"\\??\\A:";
    WINX_FILE *f;
    int result = -1;
    
    path[4] = winx_toupper(volume_letter);
    f = winx_fopen(path,"r+");
    if(f){
        result = winx_fflush(f);
        winx_fclose(f);
    }

    return result;
}
Example #2
0
/**
 * @internal
 * @brief Retrieves the NTFS data for the filesystem.
 * @param[out] pointer to the structure
 * receiving the information.
 * @return Zero for success, negative value otherwise.
 */
static int get_ntfs_data(winx_volume_information *v)
{
    WINX_FILE *f;
    int result;
    
    /* open the volume */
    f = winx_vopen(v->volume_letter);
    if(f == NULL)
        return (-1);
    
    /* get ntfs data */
    result = winx_ioctl(f,FSCTL_GET_NTFS_VOLUME_DATA,
      "get_ntfs_data: ntfs data request",NULL,0,
      &v->ntfs_data,sizeof(NTFS_DATA),NULL);
    winx_fclose(f);
    return result;
}
Example #3
0
/**
 * @internal
 * @brief Retrieves the drive geometry.
 * @param[in] hRoot handle to the
 * root directory.
 * @param[out] pointer to the structure
 * receiving the drive geometry.
 * @return Zero for success, negative
 * value otherwise.
 */
static int get_drive_geometry(HANDLE hRoot,winx_volume_information *v)
{
    FILE_FS_SIZE_INFORMATION ffs;
    IO_STATUS_BLOCK IoStatusBlock;
    NTSTATUS status;
    WINX_FILE *f;
    DISK_GEOMETRY dg;
    char buffer[32];
    
    /* get drive geometry */
    RtlZeroMemory(&ffs,sizeof(FILE_FS_SIZE_INFORMATION));
    status = NtQueryVolumeInformationFile(hRoot,&IoStatusBlock,&ffs,
                sizeof(FILE_FS_SIZE_INFORMATION),FileFsSizeInformation);
    if(!NT_SUCCESS(status)){
        strace(status,"cannot get geometry of drive %c:",v->volume_letter);
        return (-1);
    }
    
    /* fill all geometry related fields of the output structure */
    v->total_bytes = (ULONGLONG)ffs.TotalAllocationUnits.QuadPart * \
        ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->free_bytes = (ULONGLONG)ffs.AvailableAllocationUnits.QuadPart * \
        ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->total_clusters = (ULONGLONG)ffs.TotalAllocationUnits.QuadPart;
    v->bytes_per_cluster = ffs.SectorsPerAllocationUnit * ffs.BytesPerSector;
    v->sectors_per_cluster = ffs.SectorsPerAllocationUnit;
    v->bytes_per_sector = ffs.BytesPerSector;
    
    /* optional: get device capacity */
    v->device_capacity = 0;
    f = winx_vopen(v->volume_letter);
    if(f != NULL){
        if(winx_ioctl(f,IOCTL_DISK_GET_DRIVE_GEOMETRY,
          "get_drive_geometry: device geometry request",NULL,0,
          &dg,sizeof(dg),NULL) >= 0){
            v->device_capacity = dg.Cylinders.QuadPart * \
                dg.TracksPerCylinder * dg.SectorsPerTrack * dg.BytesPerSector;
            winx_bytes_to_hr(v->device_capacity,1,buffer,sizeof(buffer));
            itrace("%c: device capacity = %s",v->volume_letter,buffer);
        }
        winx_fclose(f);
    }
    return 0;
}
Example #4
0
/**
 * @internal
 * @brief Retrieves the volume dirty flag.
 * @param[out] pointer to the structure
 * receiving the volume dirty flag.
 */
static void get_volume_dirty_flag(winx_volume_information *v)
{
    WINX_FILE *f;
    ULONG dirty_flag;
    int result;
    
    /* open the volume */
    f = winx_vopen(v->volume_letter);
    if(f == NULL) return;
    
    /* get dirty flag */
    result = winx_ioctl(f,FSCTL_IS_VOLUME_DIRTY,
        "get_volume_dirty_flag: dirty flag request",
        NULL,0,&dirty_flag,sizeof(ULONG),NULL);
    winx_fclose(f);
    if(result >= 0 && (dirty_flag & VOLUME_IS_DIRTY)){
        etrace("%c: volume is dirty! Run CHKDSK to repair it.",
            v->volume_letter);
        v->is_dirty = 1;
    }
}
Example #5
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;
}
Example #6
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;
}