No need to define __USE_W32API
[reactos.git] / rosapps / fraginator / DriveVolume.cpp
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 = CreateFile
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 NULL, // 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 = GetVolumeInformation
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 = GetDiskFreeSpace
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 = GetDiskFreeSpaceEx
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_DATA 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 = FindFirstFile (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 (int 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 (FindNextFile (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 = CreateFile
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 int i;
601 Info.Fragments.clear ();
602 for (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 = CreateFile
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