1 #include "DriveVolume.h" 2 3 4 DriveVolume::DriveVolume() 5 { 6 Handle = INVALID_HANDLE_VALUE; 7 BitmapDetail = NULL; 8 ZeroMemory(&Geometry, sizeof(Geometry)); 9 } 10 11 12 DriveVolume::~DriveVolume () 13 { 14 Close (); 15 Directories.clear (); 16 Files.clear (); 17 return; 18 } 19 20 21 void DriveVolume::Close (void) 22 { 23 if (Handle != INVALID_HANDLE_VALUE) 24 { 25 CloseHandle (Handle); 26 Handle = INVALID_HANDLE_VALUE; 27 } 28 29 if (BitmapDetail != NULL) 30 { 31 HeapFree(GetProcessHeap(), 0, BitmapDetail); 32 BitmapDetail = NULL; 33 } 34 35 return; 36 } 37 38 39 // "Name" should be the drive letter followed by a colon. ie, "c:" 40 // It's a string to allow for further expansion (ie, defragging over the network?) 41 // or some other baloney reason 42 bool DriveVolume::Open (wstring Name) 43 { 44 wchar_t FileName[100]; 45 bool ReturnVal; 46 47 swprintf (FileName, L"\\\\.\\%s", Name.c_str()); 48 RootPath = Name.c_str(); 49 RootPath += L"\\"; 50 51 Handle = CreateFileW 52 ( 53 FileName, 54 MAXIMUM_ALLOWED, // access 55 FILE_SHARE_READ | FILE_SHARE_WRITE, // share type 56 NULL, // security descriptor 57 OPEN_EXISTING, // open type 58 0, // attributes (none) 59 NULL // template 60 ); 61 62 if (Handle == INVALID_HANDLE_VALUE) 63 ReturnVal = false; 64 else 65 { 66 wchar_t VolName[64]; 67 DWORD VolSN; 68 DWORD VolMaxFileLen; 69 DWORD FSFlags; 70 wchar_t FSName[64]; 71 BOOL Result; 72 73 ReturnVal = true; 74 Result = GetVolumeInformationW 75 ( 76 RootPath.c_str(), 77 VolName, 78 sizeof (VolName), 79 &VolSN, 80 &VolMaxFileLen, 81 &FSFlags, 82 FSName, 83 sizeof (FSName) 84 ); 85 86 if (Result) 87 { 88 wchar_t SerialText[10]; 89 90 VolInfo.FileSystem = FSName; 91 VolInfo.MaxNameLen = VolMaxFileLen; 92 VolInfo.Name = VolName; 93 94 swprintf (SerialText, L"%x-%x", (VolSN & 0xffff0000) >> 16, 95 VolSN & 0x0000ffff); 96 97 _wcsupr (SerialText); 98 VolInfo.Serial = SerialText; 99 } 100 else 101 { 102 VolInfo.FileSystem = L"(Unknown)"; 103 VolInfo.MaxNameLen = 255; 104 VolInfo.Name = L"(Unknown)"; 105 VolInfo.Serial = L"(Unknown)"; 106 } 107 } 108 109 return (ReturnVal); 110 } 111 112 113 bool DriveVolume::ObtainInfo (void) 114 { 115 BOOL Result; 116 DWORD BytesGot; 117 uint64 nan; 118 119 BytesGot = 0; 120 ZeroMemory (&Geometry, sizeof (Geometry)); 121 Result = DeviceIoControl 122 ( 123 Handle, 124 IOCTL_DISK_GET_DRIVE_GEOMETRY, 125 NULL, 126 0, 127 &Geometry, 128 sizeof (Geometry), 129 &BytesGot, 130 NULL 131 ); 132 133 // Call failed? Aww :( 134 if (!Result) 135 return (false); 136 137 // Get cluster size 138 DWORD SectorsPerCluster; 139 DWORD BytesPerSector; 140 DWORD FreeClusters; 141 DWORD TotalClusters; 142 143 Result = GetDiskFreeSpaceW 144 ( 145 RootPath.c_str(), 146 &SectorsPerCluster, 147 &BytesPerSector, 148 &FreeClusters, 149 &TotalClusters 150 ); 151 152 // Failed? Weird. 153 if (!Result) 154 return (false); 155 156 VolInfo.ClusterSize = SectorsPerCluster * BytesPerSector; 157 158 Result = GetDiskFreeSpaceExW 159 ( 160 RootPath.c_str(), 161 (PULARGE_INTEGER)&nan, 162 (PULARGE_INTEGER)&VolInfo.TotalBytes, 163 (PULARGE_INTEGER)&VolInfo.FreeBytes 164 ); 165 166 return (true); 167 } 168 169 170 // Get bitmap, several clusters at a time ... 171 #define CLUSTERS 4096 172 bool DriveVolume::GetBitmap (void) 173 { 174 STARTING_LCN_INPUT_BUFFER StartingLCN; 175 VOLUME_BITMAP_BUFFER *Bitmap = NULL; 176 uint32 BitmapSize; 177 DWORD BytesReturned; 178 BOOL Result; 179 180 StartingLCN.StartingLcn.QuadPart = 0; 181 182 // Allocate buffer 183 // Call FSCTL_GET_VOLUME_BITMAP once with a very small buffer 184 // This will leave the total number of clusters in Bitmap->BitmapSize and we can 185 // then correctly allocate based off that 186 // I suppose this won't work if your drive has only 40 clusters on it or so :) 187 BitmapSize = sizeof (VOLUME_BITMAP_BUFFER) + 4; 188 Bitmap = (VOLUME_BITMAP_BUFFER *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BitmapSize); 189 190 Result = DeviceIoControl 191 ( 192 Handle, 193 FSCTL_GET_VOLUME_BITMAP, 194 &StartingLCN, 195 sizeof (StartingLCN), 196 Bitmap, 197 BitmapSize, 198 &BytesReturned, 199 NULL 200 ); 201 202 // Bad result? 203 if (Result == FALSE && GetLastError() != ERROR_MORE_DATA) 204 { 205 //wprintf ("\nDeviceIoControl returned false, GetLastError() was not ERROR_MORE_DATA\n"); 206 HeapFree(GetProcessHeap(), 0, Bitmap); 207 return (false); 208 } 209 210 // Otherwise, we're good 211 BitmapSize = sizeof (VOLUME_BITMAP_BUFFER) + (Bitmap->BitmapSize.QuadPart / 8) + 1; 212 213 void *reallBitmap = HeapReAlloc(GetProcessHeap(), 0, Bitmap, BitmapSize); 214 215 if (reallBitmap == NULL) 216 { 217 // Fail "miserably" 218 wprintf(L"\nNot enough memory to read volume bitmap\n"); 219 HeapFree(GetProcessHeap(), 0, Bitmap); 220 return (false); 221 } 222 223 Bitmap = (VOLUME_BITMAP_BUFFER *)reallBitmap; 224 Result = DeviceIoControl 225 ( 226 Handle, 227 FSCTL_GET_VOLUME_BITMAP, 228 &StartingLCN, 229 sizeof (StartingLCN), 230 Bitmap, 231 BitmapSize, 232 &BytesReturned, 233 NULL 234 ); 235 236 //DWORD LastError = GetLastError (); 237 238 if (Result == FALSE) 239 { 240 wprintf (L"\nCouldn't properly read volume bitmap\n"); 241 HeapFree(GetProcessHeap(), 0, Bitmap); 242 return (false); 243 } 244 245 // Convert to a L'quick use' bitmap 246 //const int BitShift[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 247 248 VolInfo.ClusterCount = Bitmap->BitmapSize.QuadPart; 249 250 if (BitmapDetail != NULL) 251 HeapFree(GetProcessHeap(), 0, BitmapDetail); 252 253 BitmapDetail = (uint32 *) HeapAlloc(GetProcessHeap(), 0, sizeof(uint32) * (1 + (VolInfo.ClusterCount / 32))); 254 memcpy (BitmapDetail, Bitmap->Buffer, sizeof(uint32) * (1 + (VolInfo.ClusterCount / 32))); 255 256 /* 257 BitmapDetail = (Cluster *) malloc (VolInfo.ClusterCount * sizeof (Cluster)); 258 for (uint64 i = 0; i < VolInfo.ClusterCount; i++) 259 { 260 if (Bitmap->Buffer[i / 8] & BitShift[i % 8]) 261 BitmapDetail[i].Allocated = true; 262 else 263 BitmapDetail[i].Allocated = false; 264 } 265 */ 266 267 HeapFree(GetProcessHeap(), 0, Bitmap); 268 return (true); 269 } 270 271 272 bool DriveVolume::IsClusterUsed (uint64 Cluster) 273 { 274 return ((BitmapDetail[Cluster / 32] & (1 << (Cluster % 32))) ? true : false); 275 //return (BitmapDetail[Cluster].Allocated); 276 } 277 278 279 void DriveVolume::SetClusterUsed (uint64 Cluster, bool Used) 280 { 281 if (Used) 282 BitmapDetail[Cluster / 32] |= (1 << (Cluster % 32)); 283 else 284 BitmapDetail[Cluster / 32] &= ~(1 << (Cluster % 32)); 285 286 return; 287 } 288 289 290 typedef struct 291 { 292 DriveVolume *Volume; 293 double *Percent; 294 bool *QuitMonitor; 295 uint64 ClusterCount; 296 uint64 ClusterProgress; 297 } BuildDBInfo; 298 299 300 bool DriveVolume::BuildFileList (bool &QuitMonitor, double &Percent) 301 { 302 BuildDBInfo Info; 303 304 Files.clear (); 305 Directories.clear (); 306 Directories.push_back (RootPath); 307 308 Info.Volume = this; 309 Info.QuitMonitor = &QuitMonitor; 310 Info.ClusterCount = (GetVolumeInfo().TotalBytes - GetVolumeInfo().FreeBytes) / (uint64)GetVolumeInfo().ClusterSize; 311 Info.ClusterProgress = 0; 312 Info.Percent = &Percent; 313 314 ScanDirectory (RootPath, BuildDBCallback, &Info); 315 316 if (QuitMonitor == true) 317 { 318 Directories.resize (0); 319 Files.resize (0); 320 } 321 322 return (true); 323 } 324 325 326 // UserData = pointer to BuildDBInfo instance 327 bool BuildDBCallback (FileInfo &Info, HANDLE &FileHandle, void *UserData) 328 { 329 BuildDBInfo *DBInfo = (BuildDBInfo *) UserData; 330 DriveVolume *Vol = DBInfo->Volume; 331 332 Vol->Files.push_back (Info); 333 334 if (*(DBInfo->QuitMonitor) == true) 335 return (false); 336 337 DBInfo->ClusterProgress += (uint64)Info.Clusters; 338 *(DBInfo->Percent) = 339 ((double)DBInfo->ClusterProgress / (double)DBInfo->ClusterCount) * 100.0f; 340 341 return (true); 342 } 343 344 345 wstring &DriveVolume::GetDBDir (uint32 Indice) 346 { 347 return (Directories[Indice]); 348 } 349 350 351 uint32 DriveVolume::GetDBDirCount (void) 352 { 353 return (Directories.size()); 354 } 355 356 357 FileInfo &DriveVolume::GetDBFile (uint32 Indice) 358 { 359 return (Files[Indice]); 360 } 361 362 363 uint32 DriveVolume::GetDBFileCount (void) 364 { 365 return (Files.size()); 366 } 367 368 369 uint32 DriveVolume::RemoveDBFile (uint32 Indice) 370 { 371 vector<FileInfo>::iterator it; 372 373 it = Files.begin() + Indice; 374 Files.erase (it); 375 return (GetDBFileCount()); 376 } 377 378 379 bool DriveVolume::ScanDirectory (wstring DirPrefix, ScanCallback Callback, void *UserData) 380 { 381 WIN32_FIND_DATAW FindData; 382 HANDLE FindHandle; 383 wstring SearchString; 384 uint32 DirIndice; 385 386 DirIndice = Directories.size() - 1; 387 388 SearchString = DirPrefix; 389 SearchString += L"*.*"; 390 ZeroMemory (&FindData, sizeof (FindData)); 391 FindHandle = FindFirstFileW (SearchString.c_str(), &FindData); 392 393 if (FindHandle == INVALID_HANDLE_VALUE) 394 return (false); 395 396 do 397 { 398 FileInfo Info; 399 HANDLE Handle; 400 bool CallbackResult; 401 402 Handle = INVALID_HANDLE_VALUE; 403 404 // First copy over the easy stuff. 405 Info.Name = FindData.cFileName; 406 407 // DonLL't ever include '.L' and '..' 408 if (Info.Name == L"." || Info.Name == L"..") 409 continue; 410 411 //Info.FullName = DirPrefix + Info.Name; 412 Info.Size = (uint64)FindData.nFileSizeLow + ((uint64)FindData.nFileSizeHigh << (uint64)32); 413 Info.DirIndice = DirIndice; 414 415 Info.Attributes.Archive = (FindData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? 1 : 0; 416 Info.Attributes.Compressed = (FindData.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ? 1 : 0; 417 Info.Attributes.Directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; 418 Info.Attributes.Encrypted = (FindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ? 1 : 0; 419 Info.Attributes.Hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? 1 : 0; 420 Info.Attributes.Normal = (FindData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ? 1 : 0; 421 Info.Attributes.Offline = (FindData.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) ? 1 : 0; 422 Info.Attributes.ReadOnly = (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 1 : 0; 423 Info.Attributes.Reparse = (FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 424 Info.Attributes.Sparse = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) ? 1 : 0; 425 Info.Attributes.System = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? 1 : 0; 426 Info.Attributes.Temporary = (FindData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? 1 : 0; 427 Info.Attributes.AccessDenied = 0; 428 Info.Attributes.Unmovable = 0; 429 Info.Attributes.Process = 1; 430 431 Info.Clusters = 0; 432 if (GetClusterInfo (Info, Handle)) 433 { 434 uint64 TotalClusters = 0; 435 436 for (size_t i = 0; i < Info.Fragments.size(); i++) 437 { 438 TotalClusters += Info.Fragments[i].Length; 439 } 440 441 Info.Clusters = TotalClusters; 442 } 443 else 444 { 445 Info.Attributes.Unmovable = 1; 446 Info.Attributes.Process = 0; 447 } 448 449 if (Info.Attributes.Process == 1) 450 Info.Attributes.Process = ShouldProcess (Info.Attributes) ? 1 : 0; 451 452 // Run the user-defined callback function 453 CallbackResult = Callback (Info, Handle, UserData); 454 455 if (Handle != INVALID_HANDLE_VALUE) 456 CloseHandle (Handle); 457 458 if (!CallbackResult) 459 break; 460 461 // If directory, perform recursion 462 if (Info.Attributes.Directory == 1) 463 { 464 wstring Dir; 465 466 Dir = GetDBDir (Info.DirIndice); 467 Dir += Info.Name; 468 Dir += L"\\"; 469 470 Directories.push_back (Dir); 471 ScanDirectory (Dir, Callback, UserData); 472 } 473 474 } while (FindNextFileW (FindHandle, &FindData) == TRUE); 475 476 FindClose (FindHandle); 477 return (false); 478 } 479 480 481 bool DriveVolume::ShouldProcess (FileAttr Attr) 482 { 483 if (Attr.Offline == 1 || Attr.Reparse == 1 || Attr.Temporary == 1) 484 { 485 return (false); 486 } 487 488 return (true); 489 } 490 491 492 // Gets info on a file and returns a valid handle for read/write access 493 // Name, FullName, Clusters, Attributes, and Size should already be filled out. 494 // This function fills in the Fragments vector 495 bool DriveVolume::GetClusterInfo (FileInfo &Info, HANDLE &HandleResult) 496 { 497 BOOL Result; 498 HANDLE Handle; 499 wstring FullName; 500 BY_HANDLE_FILE_INFORMATION FileInfo; 501 502 Info.Fragments.resize (0); 503 504 /* 505 if (Info.Attributes.Directory == 1) 506 return (false); 507 */ 508 509 FullName = GetDBDir (Info.DirIndice) + Info.Name; 510 511 Handle = CreateFileW 512 ( 513 FullName.c_str(), 514 0, //GENERIC_READ, 515 FILE_SHARE_READ, 516 NULL, 517 OPEN_EXISTING, 518 (Info.Attributes.Directory == 1) ? FILE_FLAG_BACKUP_SEMANTICS : 0, 519 NULL 520 ); 521 522 if (Handle == INVALID_HANDLE_VALUE) 523 { 524 LPVOID lpMsgBuf; 525 526 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 527 NULL, GetLastError(), 528 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 529 (LPTSTR) &lpMsgBuf, 0, NULL ); 530 531 532 Info.Attributes.AccessDenied = 1; 533 LocalFree( lpMsgBuf ); 534 return (false); 535 } 536 537 ZeroMemory (&FileInfo, sizeof (FileInfo)); 538 Result = GetFileInformationByHandle (Handle, &FileInfo); 539 540 if (Result == FALSE) 541 { 542 Info.Attributes.AccessDenied = 1; 543 wprintf (L"GetFileInformationByHandle ('%s%s') failed\n", GetDBDir (Info.DirIndice).c_str(), 544 Info.Name.c_str()); 545 546 CloseHandle (Handle); 547 return (false); 548 } 549 550 // Get cluster allocation information 551 STARTING_VCN_INPUT_BUFFER StartingVCN; 552 RETRIEVAL_POINTERS_BUFFER *Retrieval; 553 uint64 RetSize; 554 uint64 Extents; 555 DWORD BytesReturned; 556 557 // Grab info one extent at a time, until it's done grabbing all the extent data 558 // Yeah, well it doesn't give us a way to ask L"how many extents?" that I know of ... 559 // btw, the Extents variable tends to only reflect memory usage, so when we have 560 // all the extents we look at the structure Win32 gives us for the REAL count! 561 Extents = 10; 562 Retrieval = NULL; 563 RetSize = 0; 564 StartingVCN.StartingVcn.QuadPart = 0; 565 566 do 567 { 568 Extents *= 2; 569 RetSize = sizeof (RETRIEVAL_POINTERS_BUFFER) + ((Extents - 1) * sizeof (LARGE_INTEGER) * 2); 570 571 if (Retrieval != NULL) 572 Retrieval = (RETRIEVAL_POINTERS_BUFFER *) realloc (Retrieval, RetSize); 573 else 574 Retrieval = (RETRIEVAL_POINTERS_BUFFER *) malloc (RetSize); 575 576 Result = DeviceIoControl 577 ( 578 Handle, 579 FSCTL_GET_RETRIEVAL_POINTERS, 580 &StartingVCN, 581 sizeof (StartingVCN), 582 Retrieval, 583 RetSize, 584 &BytesReturned, 585 NULL 586 ); 587 588 if (Result == FALSE) 589 { 590 if (GetLastError() != ERROR_MORE_DATA) 591 { 592 Info.Clusters = 0; 593 Info.Attributes.AccessDenied = 1; 594 Info.Attributes.Process = 0; 595 Info.Fragments.clear (); 596 CloseHandle (Handle); 597 free (Retrieval); 598 599 return (false); 600 } 601 602 Extents++; 603 } 604 } while (Result == FALSE); 605 606 // Readjust extents, as it only reflects how much memory was allocated and may not 607 // be accurate 608 Extents = Retrieval->ExtentCount; 609 610 // Ok, we have the info. Now translate it. hrmrmr 611 612 Info.Fragments.clear (); 613 for (uint64 i = 0; i < Extents; i++) 614 { 615 Extent Add; 616 617 Add.StartLCN = Retrieval->Extents[i].Lcn.QuadPart; 618 if (i != 0) 619 Add.Length = Retrieval->Extents[i].NextVcn.QuadPart - Retrieval->Extents[i - 1].NextVcn.QuadPart; 620 else 621 Add.Length = Retrieval->Extents[i].NextVcn.QuadPart - Retrieval->StartingVcn.QuadPart; 622 623 Info.Fragments.push_back (Add); 624 } 625 626 free (Retrieval); 627 HandleResult = Handle; 628 return (true); 629 } 630 631 632 bool DriveVolume::FindFreeRange (uint64 StartLCN, uint64 ReqLength, uint64 &LCNResult) 633 { 634 uint64 Max; 635 uint64 i; 636 uint64 j; 637 638 // Make sure we don't spill over our array 639 Max = VolInfo.ClusterCount - ReqLength; 640 641 for (i = StartLCN; i < Max; i++) 642 { 643 bool Found = true; 644 645 // First check the first cluster 646 if (IsClusterUsed (i)) 647 Found = false; 648 else 649 // THen check the last cluster 650 if (IsClusterUsed (i + ReqLength - 1)) 651 Found = false; 652 else 653 // Check the whole darn range. 654 for (j = (i + 1); j < (i + ReqLength - 2); j++) 655 { 656 if (IsClusterUsed (j) == true) 657 { 658 Found = false; 659 break; 660 } 661 } 662 663 if (!Found) 664 continue; 665 else 666 { 667 LCNResult = i; 668 return (true); 669 } 670 } 671 672 return (false); 673 } 674 675 676 // btw we have to move each fragment of the file, as per the Win32 API 677 bool DriveVolume::MoveFileDumb (uint32 FileIndice, uint64 NewLCN) 678 { 679 bool ReturnVal = false; 680 FileInfo Info; 681 HANDLE FileHandle; 682 wstring FullName; 683 MOVE_FILE_DATA MoveData; 684 uint64 CurrentLCN; 685 uint64 CurrentVCN; 686 687 // Set up variables 688 Info = GetDBFile (FileIndice); 689 FullName = GetDBDir (Info.DirIndice); 690 FullName += Info.Name; 691 CurrentLCN = NewLCN; 692 CurrentVCN = 0; 693 694 /* 695 if (Info.Attributes.Directory == 1) 696 { 697 // 698 } 699 */ 700 701 // Open file 702 FileHandle = CreateFileW 703 ( 704 FullName.c_str (), 705 GENERIC_READ, 706 FILE_SHARE_READ, 707 NULL, 708 OPEN_EXISTING, 709 (Info.Attributes.Directory == 1) ? FILE_FLAG_BACKUP_SEMANTICS : 0, 710 NULL 711 ); 712 713 if (FileHandle == INVALID_HANDLE_VALUE) 714 { 715 // 716 LPVOID lpMsgBuf; 717 718 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 719 NULL, GetLastError(), 720 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 721 (LPTSTR) &lpMsgBuf, 0, NULL ); 722 723 724 LocalFree (lpMsgBuf); 725 // 726 727 ReturnVal = false; 728 } 729 else 730 { 731 ReturnVal = true; // innocent until proven guilty ... 732 733 for (uint32 i = 0; i < Info.Fragments.size(); i++) 734 { 735 BOOL Result; 736 DWORD BytesReturned; 737 738 //wprintf (L"%3u", i); 739 740 MoveData.ClusterCount = Info.Fragments[i].Length; 741 MoveData.StartingLcn.QuadPart = CurrentLCN; 742 MoveData.StartingVcn.QuadPart = CurrentVCN; 743 744 MoveData.FileHandle = FileHandle; 745 746 /* 747 wprintf (L"\n"); 748 wprintf (L"StartLCN: %I64u\n", MoveData.StartingLcn.QuadPart); 749 wprintf (L"StartVCN: %I64u\n", MoveData.StartingVcn.QuadPart); 750 wprintf (L"Clusters: %u (%I64u-%I64u --> %I64u-%I64u)\n", MoveData.ClusterCount, 751 Info.Fragments[i].StartLCN, 752 Info.Fragments[i].StartLCN + MoveData.ClusterCount, 753 MoveData.StartingLcn.QuadPart, 754 MoveData.StartingLcn.QuadPart + MoveData.ClusterCount - 1); 755 wprintf (L"\n"); 756 */ 757 758 Result = DeviceIoControl 759 ( 760 Handle, 761 FSCTL_MOVE_FILE, 762 &MoveData, 763 sizeof (MoveData), 764 NULL, 765 0, 766 &BytesReturned, 767 NULL 768 ); 769 770 //wprintf (L"\b\b\b"); 771 772 if (Result == FALSE) 773 { 774 // 775 LPVOID lpMsgBuf; 776 777 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 778 NULL, GetLastError(), 779 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 780 (LPTSTR) &lpMsgBuf, 0, NULL ); 781 782 783 LocalFree( lpMsgBuf ); 784 // 785 786 ReturnVal = false; 787 goto FinishUp; // yeah, bite me 788 } 789 790 // Ok good. Now update our drive bitmap and file infos. 791 uint64 j; 792 for (j = 0; 793 j < Info.Fragments[i].Length; 794 j++) 795 { 796 SetClusterUsed (Info.Fragments[i].StartLCN + j, false); 797 SetClusterUsed (CurrentLCN + j, true); 798 //BitmapDetail[Info.Fragments[i].StartLCN + j].Allocated = false; 799 //BitmapDetail[CurrentLCN + j].Allocated = true; 800 } 801 802 CurrentLCN += Info.Fragments[i].Length; 803 CurrentVCN += Info.Fragments[i].Length; 804 } 805 806 // Update file info either way 807 FinishUp: 808 CloseHandle (FileHandle); 809 FileHandle = INVALID_HANDLE_VALUE; 810 GetClusterInfo (Files[FileIndice], FileHandle); 811 CloseHandle (FileHandle); 812 } 813 814 return (ReturnVal); 815 } 816 817 818