1 #include "DriveVolume.h" 2 3 4 DriveVolume::DriveVolume () 5 { 6 Handle = INVALID_HANDLE_VALUE; 7 BitmapDetail = NULL; 8 return; 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 free (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 *) malloc (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 free (Bitmap); 207 return (false); 208 } 209 210 // Otherwise, we're good 211 BitmapSize = sizeof (VOLUME_BITMAP_BUFFER) + (Bitmap->BitmapSize.QuadPart / 8) + 1; 212 Bitmap = (VOLUME_BITMAP_BUFFER *) realloc (Bitmap, BitmapSize); 213 Result = DeviceIoControl 214 ( 215 Handle, 216 FSCTL_GET_VOLUME_BITMAP, 217 &StartingLCN, 218 sizeof (StartingLCN), 219 Bitmap, 220 BitmapSize, 221 &BytesReturned, 222 NULL 223 ); 224 225 //DWORD LastError = GetLastError (); 226 227 if (Result == FALSE) 228 { 229 wprintf (L"\nCouldn't properly read volume bitmap\n"); 230 free (Bitmap); 231 return (false); 232 } 233 234 // Convert to a L'quick use' bitmap 235 //const int BitShift[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 236 237 VolInfo.ClusterCount = Bitmap->BitmapSize.QuadPart; 238 239 if (BitmapDetail != NULL) 240 free (BitmapDetail); 241 242 BitmapDetail = (uint32 *) malloc (sizeof(uint32) * (1 + (VolInfo.ClusterCount / 32))); 243 memcpy (BitmapDetail, Bitmap->Buffer, sizeof(uint32) * (1 + (VolInfo.ClusterCount / 32))); 244 245 /* 246 BitmapDetail = (Cluster *) malloc (VolInfo.ClusterCount * sizeof (Cluster)); 247 for (uint64 i = 0; i < VolInfo.ClusterCount; i++) 248 { 249 if (Bitmap->Buffer[i / 8] & BitShift[i % 8]) 250 BitmapDetail[i].Allocated = true; 251 else 252 BitmapDetail[i].Allocated = false; 253 } 254 */ 255 256 free (Bitmap); 257 return (true); 258 } 259 260 261 bool DriveVolume::IsClusterUsed (uint64 Cluster) 262 { 263 return ((BitmapDetail[Cluster / 32] & (1 << (Cluster % 32))) ? true : false); 264 //return (BitmapDetail[Cluster].Allocated); 265 } 266 267 268 void DriveVolume::SetClusterUsed (uint64 Cluster, bool Used) 269 { 270 if (Used) 271 BitmapDetail[Cluster / 32] |= (1 << (Cluster % 32)); 272 else 273 BitmapDetail[Cluster / 32] &= ~(1 << (Cluster % 32)); 274 275 return; 276 } 277 278 279 typedef struct 280 { 281 DriveVolume *Volume; 282 double *Percent; 283 bool *QuitMonitor; 284 uint64 ClusterCount; 285 uint64 ClusterProgress; 286 } BuildDBInfo; 287 288 289 bool DriveVolume::BuildFileList (bool &QuitMonitor, double &Percent) 290 { 291 BuildDBInfo Info; 292 293 Files.clear (); 294 Directories.clear (); 295 Directories.push_back (RootPath); 296 297 Info.Volume = this; 298 Info.QuitMonitor = &QuitMonitor; 299 Info.ClusterCount = (GetVolumeInfo().TotalBytes - GetVolumeInfo().FreeBytes) / (uint64)GetVolumeInfo().ClusterSize; 300 Info.ClusterProgress = 0; 301 Info.Percent = &Percent; 302 303 ScanDirectory (RootPath, BuildDBCallback, &Info); 304 305 if (QuitMonitor == true) 306 { 307 Directories.resize (0); 308 Files.resize (0); 309 } 310 311 return (true); 312 } 313 314 315 // UserData = pointer to BuildDBInfo instance 316 bool BuildDBCallback (FileInfo &Info, HANDLE &FileHandle, void *UserData) 317 { 318 BuildDBInfo *DBInfo = (BuildDBInfo *) UserData; 319 DriveVolume *Vol = DBInfo->Volume; 320 321 Vol->Files.push_back (Info); 322 323 if (*(DBInfo->QuitMonitor) == true) 324 return (false); 325 326 DBInfo->ClusterProgress += (uint64)Info.Clusters; 327 *(DBInfo->Percent) = 328 ((double)DBInfo->ClusterProgress / (double)DBInfo->ClusterCount) * 100.0f; 329 330 return (true); 331 } 332 333 334 wstring &DriveVolume::GetDBDir (uint32 Indice) 335 { 336 return (Directories[Indice]); 337 } 338 339 340 uint32 DriveVolume::GetDBDirCount (void) 341 { 342 return (Directories.size()); 343 } 344 345 346 FileInfo &DriveVolume::GetDBFile (uint32 Indice) 347 { 348 return (Files[Indice]); 349 } 350 351 352 uint32 DriveVolume::GetDBFileCount (void) 353 { 354 return (Files.size()); 355 } 356 357 358 uint32 DriveVolume::RemoveDBFile (uint32 Indice) 359 { 360 vector<FileInfo>::iterator it; 361 362 it = Files.begin() + Indice; 363 Files.erase (it); 364 return (GetDBFileCount()); 365 } 366 367 368 bool DriveVolume::ScanDirectory (wstring DirPrefix, ScanCallback Callback, void *UserData) 369 { 370 WIN32_FIND_DATAW FindData; 371 HANDLE FindHandle; 372 wstring SearchString; 373 uint32 DirIndice; 374 375 DirIndice = Directories.size() - 1; 376 377 SearchString = DirPrefix; 378 SearchString += L"*.*"; 379 ZeroMemory (&FindData, sizeof (FindData)); 380 FindHandle = FindFirstFileW (SearchString.c_str(), &FindData); 381 382 if (FindHandle == INVALID_HANDLE_VALUE) 383 return (false); 384 385 do 386 { 387 FileInfo Info; 388 HANDLE Handle; 389 bool CallbackResult; 390 391 Handle = INVALID_HANDLE_VALUE; 392 393 // First copy over the easy stuff. 394 Info.Name = FindData.cFileName; 395 396 // DonLL't ever include '.L' and '..' 397 if (Info.Name == L"." || Info.Name == L"..") 398 continue; 399 400 //Info.FullName = DirPrefix + Info.Name; 401 Info.Size = (uint64)FindData.nFileSizeLow + ((uint64)FindData.nFileSizeHigh << (uint64)32); 402 Info.DirIndice = DirIndice; 403 404 Info.Attributes.Archive = (FindData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? 1 : 0; 405 Info.Attributes.Compressed = (FindData.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ? 1 : 0; 406 Info.Attributes.Directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; 407 Info.Attributes.Encrypted = (FindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ? 1 : 0; 408 Info.Attributes.Hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? 1 : 0; 409 Info.Attributes.Normal = (FindData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ? 1 : 0; 410 Info.Attributes.Offline = (FindData.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) ? 1 : 0; 411 Info.Attributes.ReadOnly = (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 1 : 0; 412 Info.Attributes.Reparse = (FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 413 Info.Attributes.Sparse = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) ? 1 : 0; 414 Info.Attributes.System = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? 1 : 0; 415 Info.Attributes.Temporary = (FindData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? 1 : 0; 416 Info.Attributes.AccessDenied = 0; 417 Info.Attributes.Unmovable = 0; 418 Info.Attributes.Process = 1; 419 420 Info.Clusters = 0; 421 if (GetClusterInfo (Info, Handle)) 422 { 423 uint64 TotalClusters = 0; 424 425 for (size_t i = 0; i < Info.Fragments.size(); i++) 426 { 427 TotalClusters += Info.Fragments[i].Length; 428 } 429 430 Info.Clusters = TotalClusters; 431 } 432 else 433 { 434 Info.Attributes.Unmovable = 1; 435 Info.Attributes.Process = 0; 436 } 437 438 if (Info.Attributes.Process == 1) 439 Info.Attributes.Process = ShouldProcess (Info.Attributes) ? 1 : 0; 440 441 // Run the user-defined callback function 442 CallbackResult = Callback (Info, Handle, UserData); 443 444 if (Handle != INVALID_HANDLE_VALUE) 445 CloseHandle (Handle); 446 447 if (!CallbackResult) 448 break; 449 450 // If directory, perform recursion 451 if (Info.Attributes.Directory == 1) 452 { 453 wstring Dir; 454 455 Dir = GetDBDir (Info.DirIndice); 456 Dir += Info.Name; 457 Dir += L"\\"; 458 459 Directories.push_back (Dir); 460 ScanDirectory (Dir, Callback, UserData); 461 } 462 463 } while (FindNextFileW (FindHandle, &FindData) == TRUE); 464 465 FindClose (FindHandle); 466 return (false); 467 } 468 469 470 bool DriveVolume::ShouldProcess (FileAttr Attr) 471 { 472 if (Attr.Offline == 1 || Attr.Reparse == 1 || Attr.Temporary == 1) 473 { 474 return (false); 475 } 476 477 return (true); 478 } 479 480 481 // Gets info on a file and returns a valid handle for read/write access 482 // Name, FullName, Clusters, Attributes, and Size should already be filled out. 483 // This function fills in the Fragments vector 484 bool DriveVolume::GetClusterInfo (FileInfo &Info, HANDLE &HandleResult) 485 { 486 BOOL Result; 487 HANDLE Handle; 488 wstring FullName; 489 BY_HANDLE_FILE_INFORMATION FileInfo; 490 491 Info.Fragments.resize (0); 492 493 /* 494 if (Info.Attributes.Directory == 1) 495 return (false); 496 */ 497 498 FullName = GetDBDir (Info.DirIndice) + Info.Name; 499 500 Handle = CreateFileW 501 ( 502 FullName.c_str(), 503 0, //GENERIC_READ, 504 FILE_SHARE_READ, 505 NULL, 506 OPEN_EXISTING, 507 (Info.Attributes.Directory == 1) ? FILE_FLAG_BACKUP_SEMANTICS : 0, 508 NULL 509 ); 510 511 if (Handle == INVALID_HANDLE_VALUE) 512 { 513 LPVOID lpMsgBuf; 514 515 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 516 NULL, GetLastError(), 517 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 518 (LPTSTR) &lpMsgBuf, 0, NULL ); 519 520 521 Info.Attributes.AccessDenied = 1; 522 LocalFree( lpMsgBuf ); 523 return (false); 524 } 525 526 ZeroMemory (&FileInfo, sizeof (FileInfo)); 527 Result = GetFileInformationByHandle (Handle, &FileInfo); 528 529 if (Result == FALSE) 530 { 531 Info.Attributes.AccessDenied = 1; 532 wprintf (L"GetFileInformationByHandle ('%s%s') failed\n", GetDBDir (Info.DirIndice).c_str(), 533 Info.Name.c_str()); 534 535 CloseHandle (Handle); 536 return (false); 537 } 538 539 // Get cluster allocation information 540 STARTING_VCN_INPUT_BUFFER StartingVCN; 541 RETRIEVAL_POINTERS_BUFFER *Retrieval; 542 uint64 RetSize; 543 uint64 Extents; 544 DWORD BytesReturned; 545 546 // Grab info one extent at a time, until it's done grabbing all the extent data 547 // Yeah, well it doesn't give us a way to ask L"how many extents?" that I know of ... 548 // btw, the Extents variable tends to only reflect memory usage, so when we have 549 // all the extents we look at the structure Win32 gives us for the REAL count! 550 Extents = 10; 551 Retrieval = NULL; 552 RetSize = 0; 553 StartingVCN.StartingVcn.QuadPart = 0; 554 555 do 556 { 557 Extents *= 2; 558 RetSize = sizeof (RETRIEVAL_POINTERS_BUFFER) + ((Extents - 1) * sizeof (LARGE_INTEGER) * 2); 559 560 if (Retrieval != NULL) 561 Retrieval = (RETRIEVAL_POINTERS_BUFFER *) realloc (Retrieval, RetSize); 562 else 563 Retrieval = (RETRIEVAL_POINTERS_BUFFER *) malloc (RetSize); 564 565 Result = DeviceIoControl 566 ( 567 Handle, 568 FSCTL_GET_RETRIEVAL_POINTERS, 569 &StartingVCN, 570 sizeof (StartingVCN), 571 Retrieval, 572 RetSize, 573 &BytesReturned, 574 NULL 575 ); 576 577 if (Result == FALSE) 578 { 579 if (GetLastError() != ERROR_MORE_DATA) 580 { 581 Info.Clusters = 0; 582 Info.Attributes.AccessDenied = 1; 583 Info.Attributes.Process = 0; 584 Info.Fragments.clear (); 585 CloseHandle (Handle); 586 free (Retrieval); 587 588 return (false); 589 } 590 591 Extents++; 592 } 593 } while (Result == FALSE); 594 595 // Readjust extents, as it only reflects how much memory was allocated and may not 596 // be accurate 597 Extents = Retrieval->ExtentCount; 598 599 // Ok, we have the info. Now translate it. hrmrmr 600 601 Info.Fragments.clear (); 602 for (uint64 i = 0; i < Extents; i++) 603 { 604 Extent Add; 605 606 Add.StartLCN = Retrieval->Extents[i].Lcn.QuadPart; 607 if (i != 0) 608 Add.Length = Retrieval->Extents[i].NextVcn.QuadPart - Retrieval->Extents[i - 1].NextVcn.QuadPart; 609 else 610 Add.Length = Retrieval->Extents[i].NextVcn.QuadPart - Retrieval->StartingVcn.QuadPart; 611 612 Info.Fragments.push_back (Add); 613 } 614 615 free (Retrieval); 616 HandleResult = Handle; 617 return (true); 618 } 619 620 621 bool DriveVolume::FindFreeRange (uint64 StartLCN, uint64 ReqLength, uint64 &LCNResult) 622 { 623 uint64 Max; 624 uint64 i; 625 uint64 j; 626 627 // Make sure we don't spill over our array 628 Max = VolInfo.ClusterCount - ReqLength; 629 630 for (i = StartLCN; i < Max; i++) 631 { 632 bool Found = true; 633 634 // First check the first cluster 635 if (IsClusterUsed (i)) 636 Found = false; 637 else 638 // THen check the last cluster 639 if (IsClusterUsed (i + ReqLength - 1)) 640 Found = false; 641 else 642 // Check the whole darn range. 643 for (j = (i + 1); j < (i + ReqLength - 2); j++) 644 { 645 if (IsClusterUsed (j) == true) 646 { 647 Found = false; 648 break; 649 } 650 } 651 652 if (!Found) 653 continue; 654 else 655 { 656 LCNResult = i; 657 return (true); 658 } 659 } 660 661 return (false); 662 } 663 664 665 // btw we have to move each fragment of the file, as per the Win32 API 666 bool DriveVolume::MoveFileDumb (uint32 FileIndice, uint64 NewLCN) 667 { 668 bool ReturnVal = false; 669 FileInfo Info; 670 HANDLE FileHandle; 671 wstring FullName; 672 MOVE_FILE_DATA MoveData; 673 uint64 CurrentLCN; 674 uint64 CurrentVCN; 675 676 // Set up variables 677 Info = GetDBFile (FileIndice); 678 FullName = GetDBDir (Info.DirIndice); 679 FullName += Info.Name; 680 CurrentLCN = NewLCN; 681 CurrentVCN = 0; 682 683 /* 684 if (Info.Attributes.Directory == 1) 685 { 686 // 687 } 688 */ 689 690 // Open file 691 FileHandle = CreateFileW 692 ( 693 FullName.c_str (), 694 GENERIC_READ, 695 FILE_SHARE_READ, 696 NULL, 697 OPEN_EXISTING, 698 (Info.Attributes.Directory == 1) ? FILE_FLAG_BACKUP_SEMANTICS : 0, 699 NULL 700 ); 701 702 if (FileHandle == INVALID_HANDLE_VALUE) 703 { 704 // 705 LPVOID lpMsgBuf; 706 707 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 708 NULL, GetLastError(), 709 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 710 (LPTSTR) &lpMsgBuf, 0, NULL ); 711 712 713 LocalFree (lpMsgBuf); 714 // 715 716 ReturnVal = false; 717 } 718 else 719 { 720 ReturnVal = true; // innocent until proven guilty ... 721 722 for (uint32 i = 0; i < Info.Fragments.size(); i++) 723 { 724 BOOL Result; 725 DWORD BytesReturned; 726 727 //wprintf (L"%3u", i); 728 729 MoveData.ClusterCount = Info.Fragments[i].Length; 730 MoveData.StartingLcn.QuadPart = CurrentLCN; 731 MoveData.StartingVcn.QuadPart = CurrentVCN; 732 733 MoveData.FileHandle = FileHandle; 734 735 /* 736 wprintf (L"\n"); 737 wprintf (L"StartLCN: %I64u\n", MoveData.StartingLcn.QuadPart); 738 wprintf (L"StartVCN: %I64u\n", MoveData.StartingVcn.QuadPart); 739 wprintf (L"Clusters: %u (%I64u-%I64u --> %I64u-%I64u)\n", MoveData.ClusterCount, 740 Info.Fragments[i].StartLCN, 741 Info.Fragments[i].StartLCN + MoveData.ClusterCount, 742 MoveData.StartingLcn.QuadPart, 743 MoveData.StartingLcn.QuadPart + MoveData.ClusterCount - 1); 744 wprintf (L"\n"); 745 */ 746 747 Result = DeviceIoControl 748 ( 749 Handle, 750 FSCTL_MOVE_FILE, 751 &MoveData, 752 sizeof (MoveData), 753 NULL, 754 0, 755 &BytesReturned, 756 NULL 757 ); 758 759 //wprintf (L"\b\b\b"); 760 761 if (Result == FALSE) 762 { 763 // 764 LPVOID lpMsgBuf; 765 766 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 767 NULL, GetLastError(), 768 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 769 (LPTSTR) &lpMsgBuf, 0, NULL ); 770 771 772 LocalFree( lpMsgBuf ); 773 // 774 775 ReturnVal = false; 776 goto FinishUp; // yeah, bite me 777 } 778 779 // Ok good. Now update our drive bitmap and file infos. 780 uint64 j; 781 for (j = 0; 782 j < Info.Fragments[i].Length; 783 j++) 784 { 785 SetClusterUsed (Info.Fragments[i].StartLCN + j, false); 786 SetClusterUsed (CurrentLCN + j, true); 787 //BitmapDetail[Info.Fragments[i].StartLCN + j].Allocated = false; 788 //BitmapDetail[CurrentLCN + j].Allocated = true; 789 } 790 791 CurrentLCN += Info.Fragments[i].Length; 792 CurrentVCN += Info.Fragments[i].Length; 793 } 794 795 // Update file info either way 796 FinishUp: 797 CloseHandle (FileHandle); 798 FileHandle = INVALID_HANDLE_VALUE; 799 GetClusterInfo (Files[FileIndice], FileHandle); 800 CloseHandle (FileHandle); 801 } 802 803 return (ReturnVal); 804 } 805 806 807