1 #include "DriveVolume.h"
2
3
DriveVolume()4 DriveVolume::DriveVolume()
5 {
6 Handle = INVALID_HANDLE_VALUE;
7 BitmapDetail = NULL;
8 ZeroMemory(&Geometry, sizeof(Geometry));
9 }
10
11
~DriveVolume()12 DriveVolume::~DriveVolume ()
13 {
14 Close ();
15 Directories.clear ();
16 Files.clear ();
17 return;
18 }
19
20
Close(void)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
Open(wstring Name)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
ObtainInfo(void)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
GetBitmap(void)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
IsClusterUsed(uint64 Cluster)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
SetClusterUsed(uint64 Cluster,bool Used)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
BuildFileList(bool & QuitMonitor,double & Percent)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
BuildDBCallback(FileInfo & Info,HANDLE & FileHandle,void * UserData)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
GetDBDir(uint32 Indice)345 wstring &DriveVolume::GetDBDir (uint32 Indice)
346 {
347 return (Directories[Indice]);
348 }
349
350
GetDBDirCount(void)351 uint32 DriveVolume::GetDBDirCount (void)
352 {
353 return (Directories.size());
354 }
355
356
GetDBFile(uint32 Indice)357 FileInfo &DriveVolume::GetDBFile (uint32 Indice)
358 {
359 return (Files[Indice]);
360 }
361
362
GetDBFileCount(void)363 uint32 DriveVolume::GetDBFileCount (void)
364 {
365 return (Files.size());
366 }
367
368
RemoveDBFile(uint32 Indice)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
ScanDirectory(wstring DirPrefix,ScanCallback Callback,void * UserData)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
ShouldProcess(FileAttr Attr)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
GetClusterInfo(FileInfo & Info,HANDLE & HandleResult)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
FindFreeRange(uint64 StartLCN,uint64 ReqLength,uint64 & LCNResult)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
MoveFileDumb(uint32 FileIndice,uint64 NewLCN)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