00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00027 #include "globals.h"
00028 #include "ntfs.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 UINT MftScanDirection = MFT_SCAN_RTL;
00044 BOOLEAN MaxMftEntriesNumberUpdated = FALSE;
00045 int number_of_processed_attr_list_entries = 0;
00046
00051 NTSTATUS GetMftLayout(void)
00052 {
00053 IO_STATUS_BLOCK iosb;
00054 NTFS_DATA *ntfs_data;
00055 NTSTATUS status;
00056 ULONGLONG mft_len;
00057
00058 ntfs_data = winx_heap_alloc(sizeof(NTFS_DATA));
00059 if(ntfs_data == NULL){
00060 DebugPrint("Cannot allocate memory for GetMftLayout()!\n");
00061 out_of_memory_condition_counter ++;
00062 return STATUS_NO_MEMORY;
00063 }
00064
00065 RtlZeroMemory(ntfs_data,sizeof(NTFS_DATA));
00066 status = NtFsControlFile(winx_fileno(fVolume),NULL,NULL,NULL,&iosb, 00067 FSCTL_GET_NTFS_VOLUME_DATA,NULL,0, 00068 ntfs_data, sizeof(NTFS_DATA));
00069 if(NT_SUCCESS(status)){
00070 (void)NtWaitForSingleObject(winx_fileno(fVolume),FALSE,NULL);
00071 status = iosb.Status;
00072 }
00073 if(!NT_SUCCESS(status)){
00074 DebugPrint("Cannot get ntfs info: %x!\n",status);
00075 winx_heap_free(ntfs_data);
00076 return status;
00077 }
00078
00079 mft_len = ProcessMftSpace(ntfs_data);
00080
00081 Stat.mft_size = mft_len * bytes_per_cluster;
00082 DebugPrint("MFT size = %I64u bytes\n",Stat.mft_size);
00083 if(mft_len == 0){
00084 DebugPrint("MFT size is equal to zero!\n");
00085 winx_heap_free(ntfs_data);
00086 return STATUS_UNSUCCESSFUL;
00087 }
00088
00089 ntfs_record_size = ntfs_data->BytesPerFileRecordSegment;
00090 DebugPrint("NTFS record size = %u bytes\n",ntfs_record_size);
00091 if(ntfs_record_size == 0){
00092 DebugPrint("NTFS record size is equal to zero!\n");
00093 winx_heap_free(ntfs_data);
00094 return STATUS_UNSUCCESSFUL;
00095 }
00096
00097 max_mft_entries = Stat.mft_size / ntfs_record_size;
00098 DebugPrint("MFT contains no more than %I64u records\n",
00099 max_mft_entries);
00100
00101
00102 winx_heap_free(ntfs_data);
00103 return STATUS_SUCCESS;
00104 }
00105
00111 BOOLEAN ScanMFT(void)
00112 {
00113 PMY_FILE_INFORMATION pmfi;
00114 PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = NULL;
00115 ULONG nfrob_size;
00116 ULONGLONG mft_id, ret_mft_id;
00117 NTSTATUS status;
00118
00119 ULONGLONG tm, time, tm2, time2;
00120
00121 DebugPrint("MFT scan started!\n");
00122 number_of_processed_attr_list_entries = 0;
00123
00124
00125 status = GetMftLayout();
00126 if(!NT_SUCCESS(status)){
00127 DebugPrint("ProcessMFT() failed!\n");
00128 DebugPrint("MFT scan finished!\n");
00129 return FALSE;
00130 }
00131
00132
00133 nfrob_size = sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) + ntfs_record_size - 1;
00134 tm = winx_xtime();
00135 pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)winx_heap_alloc(nfrob_size);
00136 if(!pnfrob){
00137 DebugPrint("Not enough memory for NTFS_FILE_RECORD_OUTPUT_BUFFER!\n");
00138 out_of_memory_condition_counter ++;
00139 DebugPrint("MFT scan finished!\n");
00140 return FALSE;
00141 }
00142
00143
00144 pmfi = (PMY_FILE_INFORMATION)winx_heap_alloc(sizeof(MY_FILE_INFORMATION));
00145 if(!pmfi){
00146 DebugPrint("Not enough memory for MY_FILE_INFORMATION structure!\n");
00147 out_of_memory_condition_counter ++;
00148 winx_heap_free(pnfrob);
00149 DebugPrint("MFT scan finished!\n");
00150 return FALSE;
00151 }
00152
00153
00154
00155 MaxMftEntriesNumberUpdated = FALSE;
00156 UpdateMaxMftEntriesNumber(pnfrob,nfrob_size);
00157 mft_id = max_mft_entries - 1;
00158 DebugPrint("\n");
00159
00160 if(MaxMftEntriesNumberUpdated == FALSE){
00161 DebugPrint("UpdateMaxMftEntriesNumber() failed!\n");
00162 DebugPrint("MFT scan finished!\n");
00163 winx_heap_free(pnfrob);
00164 winx_heap_free(pmfi);
00165
00166 return FALSE;
00167 }
00168
00169 DebugPrint("+-------------------------------------------------------+\n");
00170 DebugPrint("| MFT records scanning loop begins... |\n");
00171 DebugPrint("+-------------------------------------------------------+\n");
00172 tm2 = winx_xtime();
00173
00174
00175
00176
00177 if(TRUE){
00178 MftScanDirection = MFT_SCAN_RTL;
00179 while(1){
00180 if(CheckForStopEvent()) break;
00181 status = GetMftRecord(pnfrob,nfrob_size,mft_id);
00182 if(!NT_SUCCESS(status)){
00183 if(mft_id == 0){
00184 DebugPrint("FSCTL_GET_NTFS_FILE_RECORD failed: %x!\n",status);
00185 winx_heap_free(pnfrob);
00186 winx_heap_free(pmfi);
00187 DebugPrint("MFT records scanning loop completed!\n");
00188 DebugPrint("MFT scan finished!\n");
00189
00190 return FALSE;
00191 }
00192
00193 mft_id --;
00194 continue;
00195 }
00196
00197
00198 ret_mft_id = GetMftIdFromFRN(pnfrob->FileReferenceNumber);
00199 #ifdef DETAILED_LOGGING
00200 DebugPrint("NTFS record found, id = %I64u\n",ret_mft_id);
00201 #endif
00202 AnalyseMftRecord(pnfrob,nfrob_size,pmfi);
00203
00204
00205 if(ret_mft_id == 0 || mft_id == 0) break;
00206 if(ret_mft_id > mft_id){
00207
00208 DebugPrint("Returned MFT record ID is above expected!\n");
00209 mft_id --;
00210 } else {
00211 mft_id = ret_mft_id - 1;
00212 }
00213 }
00214 }
00215
00216
00217
00218
00219
00220 winx_heap_free(pnfrob);
00221 winx_heap_free(pmfi);
00222
00223 time2 = winx_xtime() - tm2;
00224 DebugPrint("MFT records scanning loop completed in %I64u ms.\n",time2);
00225
00226
00227 BuildPaths();
00228
00229 DebugPrint("%u attribute lists entries totally processed.\n",
00230 number_of_processed_attr_list_entries);
00231 time = winx_xtime() - tm;
00232 DebugPrint("MFT scan completed in %I64u ms.\n",time);
00233 return TRUE;
00234 }
00235
00242 void UpdateMaxMftEntriesNumber(PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob,ULONG nfrob_size)
00243 {
00244 NTSTATUS status;
00245 PFILE_RECORD_HEADER pfrh;
00246
00247
00248 status = GetMftRecord(pnfrob,nfrob_size,FILE_MFT);
00249 if(!NT_SUCCESS(status)){
00250 DebugPrint("UpdateMaxMftEntriesNumber(): FSCTL_GET_NTFS_FILE_RECORD failed: %x!\n",status);
00251 return;
00252 }
00253 if(GetMftIdFromFRN(pnfrob->FileReferenceNumber) != FILE_MFT){
00254 DebugPrint("UpdateMaxMftEntriesNumber() failed - unable to get FILE_MFT record.\n");
00255 return;
00256 }
00257
00258
00259 pfrh = (PFILE_RECORD_HEADER)pnfrob->FileRecordBuffer;
00260 if(!IsFileRecord(pfrh)){
00261 DebugPrint("UpdateMaxMftEntriesNumber() failed - FILE_MFT record has invalid type %u.\n",
00262 pfrh->Ntfs.Type);
00263 return;
00264 }
00265 if(!(pfrh->Flags & 0x1)){
00266 DebugPrint("UpdateMaxMftEntriesNumber() failed - FILE_MFT record marked as free.\n");
00267 return;
00268 }
00269
00270 EnumerateAttributes(pfrh,UpdateMaxMftEntriesNumberCallback,NULL);
00271 }
00272
00275 void __stdcall UpdateMaxMftEntriesNumberCallback(PATTRIBUTE pattr,PMY_FILE_INFORMATION pmfi)
00276 {
00277 PNONRESIDENT_ATTRIBUTE pnr_attr;
00278
00279
00280 (void)pmfi;
00281
00282 if(pattr->Nonresident && pattr->AttributeType == AttributeData){
00283 pnr_attr = (PNONRESIDENT_ATTRIBUTE)pattr;
00284 if(ntfs_record_size){
00285 max_mft_entries = pnr_attr->DataSize / ntfs_record_size;
00286 Stat.mft_size = pnr_attr->DataSize;
00287
00288
00289
00290
00291 MaxMftEntriesNumberUpdated = TRUE;
00292 }
00293 DebugPrint("MFT contains no more than %I64u records (more accurately)\n",
00294 max_mft_entries);
00295 }
00296 }
00297
00306 NTSTATUS GetMftRecord(PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob,
00307 ULONG nfrob_size,ULONGLONG mft_id)
00308 {
00309 NTFS_FILE_RECORD_INPUT_BUFFER nfrib;
00310 IO_STATUS_BLOCK iosb;
00311 NTSTATUS status;
00312
00313 nfrib.FileReferenceNumber = mft_id;
00314
00315 RtlZeroMemory(pnfrob,nfrob_size);
00316 status = NtFsControlFile(winx_fileno(fVolume),NULL,NULL,NULL,&iosb, 00317 FSCTL_GET_NTFS_FILE_RECORD, 00318 &nfrib,sizeof(nfrib), 00319 pnfrob, nfrob_size);
00320 if(NT_SUCCESS(status)){
00321 (void)NtWaitForSingleObject(winx_fileno(fVolume),FALSE,NULL);
00322 status = iosb.Status;
00323 }
00324 return status;
00325 }
00326
00335 int UpdateAttributeName(PFILENAME pfn,PMY_FILE_INFORMATION pmfi)
00336 {
00337 short *buffer;
00338 UNICODE_STRING us;
00339
00340
00341 if(pmfi->Name[0] == 0){
00342 DebugPrint("MftRecord has empty filename, MftId = %I64u, Parent MftId = %I64u\n",
00343 pmfi->BaseMftId,pmfi->ParentDirectoryMftId);
00344 return (-1);
00345 }
00346
00347
00348 buffer = winx_heap_alloc(MAX_NTFS_PATH * sizeof(short));
00349 if(buffer == NULL){
00350 DebugPrint("Cannot allocate memory for buffer in UpdateAttributeName()!\n");
00351 out_of_memory_condition_counter ++;
00352 return (-1);
00353 }
00354 if(pfn->name.Buffer[0])
00355 (void)_snwprintf(buffer,MAX_NTFS_PATH,L"%s:%s",pmfi->Name,pfn->name.Buffer);
00356 else
00357 (void)wcsncpy(buffer,pmfi->Name,MAX_NTFS_PATH);
00358 buffer[MAX_NTFS_PATH - 1] = 0;
00359
00360 if(!RtlCreateUnicodeString(&us,buffer)){
00361 DebugPrint("UpdateAttributeName: Cannot allocate memory for new name!\n");
00362 out_of_memory_condition_counter ++;
00363 winx_heap_free(buffer);
00364 return (-1);
00365 }
00366
00367 RtlFreeUnicodeString(&(pfn->name));
00368 pfn->name.Buffer = us.Buffer;
00369 pfn->name.Length = us.Length;
00370 pfn->name.MaximumLength = us.MaximumLength;
00371
00372
00373
00374 winx_heap_free(buffer);
00375 return 0;
00376 }
00377
00386 void AnalyseMftRecord(PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob,
00387 ULONG nfrob_size,PMY_FILE_INFORMATION pmfi)
00388 {
00389 PFILE_RECORD_HEADER pfrh;
00390 #ifdef DETAILED_LOGGING
00391 USHORT Flags;
00392 #endif
00393 PFILENAME pfn, next_pfn, head;
00394 BOOLEAN DirectoryAdded;
00395
00396
00397 pfrh = (PFILE_RECORD_HEADER)pnfrob->FileRecordBuffer;
00398
00399 if(!IsFileRecord(pfrh)) return;
00400 if(!(pfrh->Flags & 0x1)) return;
00401
00402
00403 #ifdef DETAILED_LOGGING
00404 Flags = pfrh->Flags;
00405 if(Flags & 0x2) DebugPrint("Directory\n");
00406 #endif
00407
00408 if(pfrh->BaseFileRecord){
00409
00410
00411
00412 return;
00413 }
00414
00415
00416 pmfi->BaseMftId = GetMftIdFromFRN(pnfrob->FileReferenceNumber);
00417 pmfi->ParentDirectoryMftId = FILE_root;
00418 pmfi->Flags = 0x0;
00419
00420
00421 pmfi->IsDirectory = (pfrh->Flags & 0x2) ? TRUE : FALSE;
00422
00423 pmfi->IsReparsePoint = FALSE;
00424 pmfi->NameType = 0x0;
00425 memset(pmfi->Name,0,MAX_NTFS_PATH);
00426
00427
00428 EnumerateAttributes(pfrh,AnalyseAttributeCallback,pmfi);
00429
00430
00431 EnumerateAttributes(pfrh,AnalyseAttributeListCallback,pmfi);
00432
00433
00434 head = filelist;
00435 for(pfn = filelist; pfn != NULL;){
00436 if(MftScanDirection == MFT_SCAN_RTL){
00437 if(pfn->BaseMftId > pmfi->BaseMftId) break;
00438 } else {
00439 if(pfn->BaseMftId < pmfi->BaseMftId) break;
00440 }
00441 next_pfn = pfn->next_ptr;
00442 if(pfn->ParentDirectoryMftId == pmfi->ParentDirectoryMftId && 00443 pfn->BaseMftId == pmfi->BaseMftId){
00444 if(UpdateAttributeName(pfn,pmfi) < 0){
00445 winx_list_remove_item((list_entry **)(void *)&filelist,(list_entry *)pfn);
00446 if(filelist == NULL) break;
00447 if(filelist != head){
00448 head = filelist;
00449 pfn = next_pfn;
00450 continue;
00451 }
00452 }
00453 }
00454 pfn = next_pfn;
00455 if(pfn == head) break;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464 if(pmfi->IsDirectory){
00465
00466 DirectoryAdded = FALSE;
00467 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
00468
00469
00470
00471
00472 if(MftScanDirection == MFT_SCAN_RTL){
00473 if(pfn->BaseMftId > pmfi->BaseMftId) break;
00474 } else {
00475 if(pfn->BaseMftId < pmfi->BaseMftId) break;
00476 }
00477 if(!wcscmp(pfn->name.Buffer,pmfi->Name) && 00478 (pfn->ParentDirectoryMftId == pmfi->ParentDirectoryMftId) && 00479 (pfn->BaseMftId == pmfi->BaseMftId))
00480 DirectoryAdded = TRUE;
00481 if(pfn->next_ptr == filelist) break;
00482 }
00483 if(!DirectoryAdded) AddResidentDirectoryToFileList(pmfi);
00484 }
00485
00486
00487 UpdateClusterMapAndStatistics(pmfi);
00488
00489 #ifdef DETAILED_LOGGING
00490 DebugPrint("\n");
00491 #endif
00492 }
00493
00504 void EnumerateAttributes(PFILE_RECORD_HEADER pfrh,
00505 ATTRHANDLER_PROC ahp,PMY_FILE_INFORMATION pmfi)
00506 {
00507 PATTRIBUTE pattr;
00508 ULONG attr_length;
00509 USHORT attr_offset;
00510
00511 attr_offset = pfrh->AttributeOffset;
00512 pattr = (PATTRIBUTE)((char *)pfrh + attr_offset);
00513
00514 while(pattr){
00515 if(CheckForStopEvent()) break;
00516
00517
00518 if(attr_offset + sizeof(ATTRIBUTE) > pfrh->BytesInUse || 00519 attr_offset + sizeof(ATTRIBUTE) > ntfs_record_size) break;
00520
00521
00522 if(pattr->AttributeType == 0xffffffff) break;
00523 if(pattr->AttributeType == 0x0) break;
00524 if(pattr->Length == 0) break;
00525
00526
00527 if(attr_offset + pattr->Length > pfrh->BytesInUse || 00528 attr_offset + pattr->Length > ntfs_record_size) break;
00529
00530
00531 if(pattr->Nonresident){
00532 if(pattr->Length < (sizeof(NONRESIDENT_ATTRIBUTE) - sizeof(ULONGLONG))){
00533 DebugPrint("Nonresident attribute length is invalid!\n");
00534 break;
00535 }
00536 } else {
00537 if(pattr->Length < sizeof(RESIDENT_ATTRIBUTE)){
00538 DebugPrint("Resident attribute length is invalid!\n");
00539 break;
00540 }
00541 }
00542
00543
00544 ahp(pattr,pmfi);
00545
00546
00547 attr_length = pattr->Length;
00548 attr_offset += (USHORT)(attr_length);
00549 pattr = (PATTRIBUTE)((char *)pattr + attr_length);
00550 }
00551 }
00552
00555 void __stdcall AnalyseAttributeCallback(PATTRIBUTE pattr,PMY_FILE_INFORMATION pmfi)
00556 {
00557 if(pattr->AttributeType != AttributeAttributeList)
00558 AnalyseAttribute(pattr,pmfi);
00559 }
00560
00563 void __stdcall AnalyseAttributeListCallback(PATTRIBUTE pattr,PMY_FILE_INFORMATION pmfi)
00564 {
00565 if(pattr->AttributeType == AttributeAttributeList)
00566 AnalyseAttribute(pattr,pmfi);
00567 }
00568
00572 void AnalyseAttribute(PATTRIBUTE pattr,PMY_FILE_INFORMATION pmfi)
00573 {
00574 if(pattr->Nonresident) AnalyseNonResidentAttribute((PNONRESIDENT_ATTRIBUTE)pattr,pmfi);
00575 else AnalyseResidentAttribute((PRESIDENT_ATTRIBUTE)pattr,pmfi);
00576 }
00577
00589 void AnalyseResidentAttribute(PRESIDENT_ATTRIBUTE pr_attr,PMY_FILE_INFORMATION pmfi)
00590 {
00591 if(pr_attr->ValueOffset == 0 || pr_attr->ValueLength == 0){
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 return;
00603 }
00604
00605 switch(pr_attr->Attribute.AttributeType){
00606 case AttributeStandardInformation:
00607 GetFileFlags(pr_attr,pmfi); break;
00608
00609 case AttributeFileName:
00610 GetFileName(pr_attr,pmfi); break;
00611
00612 case AttributeVolumeInformation:
00613 GetVolumeInformationData(pr_attr); break;
00614
00615 case AttributeAttributeList:
00616
00617 AnalyseResidentAttributeList(pr_attr,pmfi);
00618 break;
00619
00620
00621
00622
00623 case AttributeReparsePoint:
00624 CheckReparsePointResident(pr_attr,pmfi);
00625 break;
00626
00627 default:
00628 break;
00629 }
00630 }
00631
00639 void GetFileFlags(PRESIDENT_ATTRIBUTE pr_attr,PMY_FILE_INFORMATION pmfi)
00640 {
00641 PSTANDARD_INFORMATION psi;
00642 ULONG Flags;
00643
00644 psi = (PSTANDARD_INFORMATION)((char *)pr_attr + pr_attr->ValueOffset);
00645 if(pr_attr->ValueLength < 48){
00646 DebugPrint("STANDARD_INFORMATION attribute is too short!\n");
00647 } else {
00648 Flags = psi->FileAttributes;
00649 pmfi->Flags = Flags;
00650 }
00651 }
00652
00661 void GetFileName(PRESIDENT_ATTRIBUTE pr_attr,PMY_FILE_INFORMATION pmfi)
00662 {
00663 PFILENAME_ATTRIBUTE pfn_attr;
00664 short *name;
00665 UCHAR name_type;
00666 ULONGLONG parent_mft_id;
00667
00668 pfn_attr = (PFILENAME_ATTRIBUTE)((char *)pr_attr + pr_attr->ValueOffset);
00669 if(pr_attr->ValueLength < sizeof(FILENAME_ATTRIBUTE)){
00670 DebugPrint("FILENAME_ATTRIBUTE is too short!\n");
00671 return;
00672 }
00673
00674 parent_mft_id = GetMftIdFromFRN(pfn_attr->DirectoryFileReferenceNumber);
00675
00676 if(pfn_attr->NameLength){
00677 name = (short *)winx_heap_alloc((pfn_attr->NameLength + 1) * sizeof(short));
00678 if(!name){
00679 DebugPrint("Cannot allocate memory for GetFileName()!\n");
00680 out_of_memory_condition_counter ++;
00681 return;
00682 }
00683 (void)wcsncpy(name,pfn_attr->Name,pfn_attr->NameLength);
00684 name[pfn_attr->NameLength] = 0;
00685
00686 if(name[0] == 0) DebugPrint("Empty filename found ;)\n");
00687 if(parent_mft_id == pmfi->BaseMftId && pmfi->BaseMftId != FILE_root)
00688 DebugPrint("Recursion found - file identifies themselves as a parent ;)\n");
00689 if(name[0] && (parent_mft_id != pmfi->BaseMftId || pmfi->BaseMftId == FILE_root)){
00690
00691 pmfi->ParentDirectoryMftId = parent_mft_id;
00692
00693 name_type = pfn_attr->NameType;
00694 UpdateFileName(pmfi,name,name_type);
00695 }
00696 winx_heap_free(name);
00697 } else DebugPrint("GetFileName: Empty name found, MFT ID = %I64u\n",pmfi->BaseMftId);
00698 }
00699
00709 void UpdateFileName(PMY_FILE_INFORMATION pmfi,WCHAR *name,UCHAR name_type)
00710 {
00711
00712 if(pmfi->Name[0] == 0 || pmfi->NameType == FILENAME_DOS || 00713 ((pmfi->NameType & FILENAME_WIN32) && (name_type == FILENAME_POSIX))){
00714 (void)wcsncpy(pmfi->Name,name,MAX_NTFS_PATH);
00715 pmfi->Name[MAX_NTFS_PATH-1] = 0;
00716 pmfi->NameType = name_type;
00717 }
00718 }
00719
00725 void GetVolumeInformationData(PRESIDENT_ATTRIBUTE pr_attr)
00726 {
00727 PVOLUME_INFORMATION pvi;
00728 ULONG mj_ver, mn_ver;
00729 BOOLEAN dirty_flag = FALSE;
00730
00731 pvi = (PVOLUME_INFORMATION)((char *)pr_attr + pr_attr->ValueOffset);
00732 if(pr_attr->ValueLength < sizeof(VOLUME_INFORMATION)){
00733 DebugPrint("VOLUME_INFORMATION is too short!\n");
00734 return;
00735 }
00736
00737 mj_ver = (ULONG)pvi->MajorVersion;
00738 mn_ver = (ULONG)pvi->MinorVersion;
00739 if(pvi->Flags & 0x1) dirty_flag = TRUE;
00740 DebugPrint("NTFS Version %u.%u\n",mj_ver,mn_ver);
00741 if(dirty_flag) DebugPrint("Volume is dirty!\n");
00742 }
00743
00751 void CheckReparsePointResident(PRESIDENT_ATTRIBUTE pr_attr,PMY_FILE_INFORMATION pmfi)
00752 {
00753 PREPARSE_POINT prp;
00754 ULONG tag;
00755
00756 prp = (PREPARSE_POINT)((char *)pr_attr + pr_attr->ValueOffset);
00757 if(pr_attr->ValueLength >= sizeof(ULONG)){
00758 tag = prp->ReparseTag;
00759 DebugPrint("Reparse tag = 0x%x\n",tag);
00760 } else {
00761 DebugPrint("REPARSE_POINT is too short!\n");
00762 }
00763
00764 pmfi->IsReparsePoint = TRUE;
00765 }
00766
00776 void AnalyseResidentAttributeList(PRESIDENT_ATTRIBUTE pr_attr,PMY_FILE_INFORMATION pmfi)
00777 {
00778 PATTRIBUTE_LIST attr_list_entry;
00779 USHORT length;
00780
00781 attr_list_entry = (PATTRIBUTE_LIST)((char *)pr_attr + pr_attr->ValueOffset);
00782
00783 while(TRUE){
00784 if( ((char *)attr_list_entry + sizeof(ATTRIBUTE_LIST) - sizeof(attr_list_entry->AlignmentOrReserved)) >
00785 ((char *)pr_attr + pr_attr->ValueOffset + pr_attr->ValueLength) ) break;
00786 if(CheckForStopEvent()) break;
00787
00788 if(attr_list_entry->AttributeType == 0xffffffff) break;
00789 if(attr_list_entry->AttributeType == 0x0) break;
00790 if(attr_list_entry->Length == 0) break;
00791
00792 AnalyseAttributeFromAttributeList(attr_list_entry,pmfi);
00793
00794 length = attr_list_entry->Length;
00795 attr_list_entry = (PATTRIBUTE_LIST)((char *)attr_list_entry + length);
00796 }
00797 }
00798
00805 void AnalyseAttributeFromAttributeList(PATTRIBUTE_LIST attr_list_entry,PMY_FILE_INFORMATION pmfi)
00806 {
00807 ULONGLONG child_record_mft_id;
00808 ATTRIBUTE_TYPE attr_type;
00809 USHORT attr_number;
00810 UCHAR name_length = 0;
00811 short *attr_name = NULL;
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 name_length = attr_list_entry->NameLength;
00822 if(attr_list_entry->NameOffset && name_length){
00823 attr_name = winx_heap_alloc((name_length + 1) * sizeof(short));
00824 if(attr_name == NULL){
00825 DebugPrint("Cannot allocate %u bytes of memory for AnalyseAttributeFromAttributeList()!\n",
00826 (name_length + 1) * sizeof(short));
00827 out_of_memory_condition_counter ++;
00828 return;
00829 }
00830 memcpy(attr_name,
00831 (char *)attr_list_entry + attr_list_entry->NameOffset,
00832 name_length * sizeof(short));
00833 attr_name[name_length] = 0;
00834 if(attr_name[0] == 0){
00835 winx_heap_free(attr_name);
00836 attr_name = NULL;
00837 }
00838 }
00839
00840
00841
00842 attr_type = attr_list_entry->AttributeType;
00843
00844
00845 child_record_mft_id = GetMftIdFromFRN(attr_list_entry->FileReferenceNumber);
00846
00847
00848 attr_number = attr_list_entry->AttributeNumber;
00849
00850
00851 AnalyseAttributeFromMftRecord(child_record_mft_id,attr_type,attr_name,attr_number,pmfi);
00852
00853
00854 if(attr_name) winx_heap_free(attr_name);
00855 }
00856
00868 void AnalyseAttributeFromMftRecord(ULONGLONG mft_id,ATTRIBUTE_TYPE attr_type,
00869 short *attr_name,USHORT attr_number,PMY_FILE_INFORMATION pmfi)
00870 {
00871 PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = NULL;
00872 ULONG nfrob_size;
00873 NTSTATUS status;
00874 PFILE_RECORD_HEADER pfrh;
00875
00876
00877
00878
00879
00880 if(mft_id == pmfi->BaseMftId){
00881
00882 return;
00883 }
00884
00885
00886 nfrob_size = sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER) + ntfs_record_size - 1;
00887 pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)winx_heap_alloc(nfrob_size);
00888 if(!pnfrob){
00889 DebugPrint("AnalyseAttributeFromMftRecord():\n");
00890 DebugPrint("Not enough memory for NTFS_FILE_RECORD_OUTPUT_BUFFER!\n");
00891 out_of_memory_condition_counter ++;
00892 return;
00893 }
00894
00895
00896 status = GetMftRecord(pnfrob,nfrob_size,mft_id);
00897 if(!NT_SUCCESS(status)){
00898 DebugPrint("AnalyseAttributeFromMftRecord(): FSCTL_GET_NTFS_FILE_RECORD failed: %x!\n",status);
00899 winx_heap_free(pnfrob);
00900 return;
00901 }
00902 if(GetMftIdFromFRN(pnfrob->FileReferenceNumber) != mft_id){
00903 DebugPrint("AnalyseAttributeFromAttributeList() failed - unable to get %I64u record.\n",mft_id);
00904 winx_heap_free(pnfrob);
00905 return;
00906 }
00907
00908
00909 pfrh = (PFILE_RECORD_HEADER)pnfrob->FileRecordBuffer;
00910 if(!IsFileRecord(pfrh)){
00911 DebugPrint("AnalyseAttributeFromMftRecord() failed - %I64u record has invalid type %u.\n",
00912 mft_id,pfrh->Ntfs.Type);
00913 winx_heap_free(pnfrob);
00914 return;
00915 }
00916 if(!(pfrh->Flags & 0x1)){
00917 DebugPrint("AnalyseAttributeFromMftRecord() failed\n");
00918 DebugPrint("%I64u record marked as free.\n",mft_id);
00919 winx_heap_free(pnfrob);
00920 return;
00921 }
00922
00923 if(pfrh->BaseFileRecord == 0){
00924 DebugPrint("AnalyseAttributeFromMftRecord() failed - %I64u is not a child record.\n",mft_id);
00925 winx_heap_free(pnfrob);
00926 return;
00927 }
00928
00929
00930 AnalyseSingleAttribute(mft_id,pfrh,attr_type,attr_name,attr_number,pmfi);
00931
00932
00933 winx_heap_free(pnfrob);
00934 }
00935
00938 void AnalyseSingleAttribute(ULONGLONG mft_id,PFILE_RECORD_HEADER pfrh,
00939 ATTRIBUTE_TYPE attr_type,short *attr_name,USHORT attr_number,PMY_FILE_INFORMATION pmfi)
00940 {
00941 int name_length;
00942 PATTRIBUTE pattr;
00943 ULONG attr_length;
00944 USHORT attr_offset;
00945 short *name = NULL;
00946 BOOLEAN attribute_found = FALSE;
00947 char *resident_status = "";
00948
00949 attr_offset = pfrh->AttributeOffset;
00950 pattr = (PATTRIBUTE)((char *)pfrh + attr_offset);
00951
00952 while(pattr){
00953 if(CheckForStopEvent()) break;
00954
00955
00956 if(attr_offset + sizeof(ATTRIBUTE) > pfrh->BytesInUse || 00957 attr_offset + sizeof(ATTRIBUTE) > ntfs_record_size) break;
00958
00959
00960 if(pattr->AttributeType == 0xffffffff) break;
00961 if(pattr->AttributeType == 0x0) break;
00962 if(pattr->Length == 0) break;
00963
00964
00965 if(attr_offset + pattr->Length > pfrh->BytesInUse || 00966 attr_offset + pattr->Length > ntfs_record_size) break;
00967
00968
00969 if(pattr->Nonresident){
00970 if(pattr->Length < (sizeof(NONRESIDENT_ATTRIBUTE) - sizeof(ULONGLONG))){
00971 DebugPrint("Nonresident attribute length is invalid!\n");
00972 break;
00973 }
00974 } else {
00975 if(pattr->Length < sizeof(RESIDENT_ATTRIBUTE)){
00976 DebugPrint("Resident attribute length is invalid!\n");
00977 break;
00978 }
00979 }
00980
00981
00982 if(pattr->AttributeType == attr_type){
00983 if(pattr->NameOffset && pattr->NameLength){
00984 name = (short *)((char *)pattr + pattr->NameOffset);
00985 if(name[0] == 0) name = NULL;
00986 }
00987 if(attr_name == NULL){
00988 if(name == NULL && pattr->AttributeNumber == attr_number)
00989 attribute_found = TRUE;
00990 } else {
00991 if(name != NULL){
00992 name_length = wcslen(attr_name);
00993 if(name_length == pattr->NameLength){
00994 if(memcmp((void *)attr_name,(void *)name,name_length * sizeof(short)) == 0){
00995 if(pattr->AttributeNumber == attr_number)
00996 attribute_found = TRUE;
00997 }
00998 }
00999 }
01000 }
01001 }
01002
01003 if(attribute_found){
01004 if(pattr->Nonresident) resident_status = "Nonresident";
01005 else resident_status = "Resident";
01006
01007 DebugPrint("AttrListEntry: Base MftId = %I64u, MftId = %I64u, Attribute Type = 0x%x, Attribute Number = %u, %s\n",
01008 pmfi->BaseMftId,mft_id,(UINT)attr_type,(UINT)attr_number,resident_status);
01009 if(pattr->Nonresident) AnalyseNonResidentAttribute((PNONRESIDENT_ATTRIBUTE)pattr,pmfi);
01010 else AnalyseResidentAttribute((PRESIDENT_ATTRIBUTE)pattr,pmfi);
01011 number_of_processed_attr_list_entries ++;
01012 return;
01013 }
01014
01015
01016 attr_length = pattr->Length;
01017 attr_offset += (USHORT)(attr_length);
01018 pattr = (PATTRIBUTE)((char *)pattr + attr_length);
01019 }
01020 }
01021
01025 ATTRIBUTE_NAME __default_attribute_names[] = {
01026 {AttributeAttributeList, L"$ATTRIBUTE_LIST" },
01027 {AttributeEA, L"$EA" },
01028 {AttributeEAInformation, L"$EA_INFORMATION" },
01029 {AttributeSecurityDescriptor, L"$SECURITY_DESCRIPTOR" },
01030 {AttributeData, L"$DATA" },
01031 {AttributeIndexRoot, L"$INDEX_ROOT" },
01032 {AttributeIndexAllocation, L"$INDEX_ALLOCATION" },
01033 {AttributeBitmap, L"$BITMAP" },
01034 {AttributeReparsePoint, L"$REPARSE_POINT" },
01035 {AttributeLoggedUtulityStream, L"$LOGGED_UTILITY_STREAM"},
01036 {0, NULL }
01037 };
01038
01045 short *GetDefaultAttributeName(ATTRIBUTE_TYPE attr_type)
01046 {
01047 int i;
01048
01049 for(i = 0;; i++){
01050 if(__default_attribute_names[i].AttributeName == NULL) break;
01051 if(__default_attribute_names[i].AttributeType == attr_type) break;
01052 }
01053 return __default_attribute_names[i].AttributeName;
01054 }
01055
01067 void AnalyseNonResidentAttribute(PNONRESIDENT_ATTRIBUTE pnr_attr,PMY_FILE_INFORMATION pmfi)
01068 {
01069 ATTRIBUTE_TYPE attr_type;
01070 WCHAR *default_attr_name = NULL;
01071 short *attr_name;
01072 BOOLEAN NonResidentAttrListFound = FALSE;
01073
01074
01075 attr_type = pnr_attr->Attribute.AttributeType;
01076 default_attr_name = GetDefaultAttributeName(attr_type);
01077
01078
01079 if(default_attr_name == NULL){
01080 DebugPrint("Nonresident attribute of unknown type 0x%x found!\n",(UINT)attr_type);
01081 return;
01082 }
01083
01084
01085 attr_name = (short *)winx_heap_alloc((MAX_NTFS_PATH + 1) * sizeof(short));
01086 if(!attr_name){
01087 DebugPrint("Cannot allocate memory for attr_name in AnalyseNonResidentAttribute()!\n");
01088 out_of_memory_condition_counter ++;
01089 return;
01090 }
01091
01092
01093 if(attr_type == AttributeAttributeList){
01094 DebugPrint("Nonresident AttributeList found!\n");
01095 NonResidentAttrListFound = TRUE;
01096 }
01097
01098 if(attr_type == AttributeReparsePoint)
01099 pmfi->IsReparsePoint = TRUE;
01100
01101
01102
01103
01104
01105 attr_name[0] = 0;
01106 if(pnr_attr->Attribute.NameLength){
01107
01108 (void)wcsncpy(attr_name,(short *)((char *)pnr_attr + pnr_attr->Attribute.NameOffset),
01109 pnr_attr->Attribute.NameLength);
01110 attr_name[pnr_attr->Attribute.NameLength] = 0;
01111 }
01112
01113 if(attr_name[0] == 0){
01114 (void)wcsncpy(attr_name,default_attr_name,MAX_NTFS_PATH);
01115 attr_name[MAX_NTFS_PATH - 1] = 0;
01116 }
01117
01118
01119 if(wcscmp(attr_name,L"$DATA") == 0) attr_name[0] = 0;
01120
01121
01122 if(wcscmp(attr_name,L"$I30") == 0) attr_name[0] = 0;
01123 if(wcscmp(attr_name,L"$INDEX_ALLOCATION") == 0) attr_name[0] = 0;
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137 if(NonResidentAttrListFound) DebugPrint("%ws:%ws\n",pmfi->Name,attr_name);
01138
01139
01140 if(winx_wcsistr(pmfi->Name,L"$BadClus")){
01141
01142
01143 } else {
01144 ProcessRunList(attr_name,pnr_attr,pmfi,NonResidentAttrListFound);
01145 }
01146
01147
01148 winx_heap_free(attr_name);
01149 }
01150
01153 static ULONG RunLength(PUCHAR run)
01154 {
01155 return (*run & 0xf) + ((*run >> 4) & 0xf) + 1;
01156 }
01157
01160 static LONGLONG RunLCN(PUCHAR run)
01161 {
01162 LONG i;
01163 UCHAR n1 = *run & 0xf;
01164 UCHAR n2 = (*run >> 4) & 0xf;
01165 LONGLONG lcn = (n2 == 0) ? 0 : (LONGLONG)(((signed char *)run)[n1 + n2]);
01166
01167 for(i = n1 + n2 - 1; i > n1; i--)
01168 lcn = (lcn << 8) + run[i];
01169 return lcn;
01170 }
01171
01174 static ULONGLONG RunCount(PUCHAR run)
01175 {
01176 ULONG i;
01177 UCHAR n = *run & 0xf;
01178 ULONGLONG count = 0;
01179
01180 for(i = n; i > 0; i--)
01181 count = (count << 8) + run[i];
01182 return count;
01183 }
01184
01195 void ProcessRunList(WCHAR *full_path,
01196 PNONRESIDENT_ATTRIBUTE pnr_attr,PMY_FILE_INFORMATION pmfi,
01197 BOOLEAN is_attr_list)
01198 {
01199 PUCHAR run;
01200 ULONGLONG lcn, vcn, length;
01201 PFILENAME pfn;
01202 BOOLEAN is_compressed = (pnr_attr->Attribute.Flags & 0x1) ? TRUE : FALSE;
01203
01204
01205
01206
01207
01208
01209
01210 pfn = FindFileListEntryForTheAttribute(full_path,pmfi);
01211 if(pfn == NULL) return;
01212
01213 if(is_compressed) pfn->is_compressed = TRUE;
01214
01215
01216 lcn = 0; vcn = pnr_attr->LowVcn;
01217 run = (PUCHAR)((char *)pnr_attr + pnr_attr->RunArrayOffset);
01218 while(*run){
01219 lcn += RunLCN(run);
01220 length = RunCount(run);
01221
01222
01223 if(RunLCN(run)){
01224
01225 if(!CheckBlock(lcn,length)){
01226 DebugPrint("Error in MFT found, run Check Disk program!\n");
01227 break;
01228 }
01229 ProcessRun(full_path,pmfi,pfn,vcn,length,lcn);
01230 }
01231
01232
01233 run += RunLength(run);
01234 vcn += length;
01235 }
01236
01237
01238 if(is_attr_list) AnalyseNonResidentAttributeList(pfn,pmfi,pnr_attr->InitializedSize);
01239 }
01240
01249 void AnalyseNonResidentAttributeList(PFILENAME pfn,PMY_FILE_INFORMATION pmfi,ULONGLONG size)
01250 {
01251 ULONGLONG clusters_to_read;
01252 char *cluster;
01253 char *current_cluster;
01254 PBLOCKMAP block;
01255 ULONGLONG lsn;
01256 NTSTATUS status;
01257 PATTRIBUTE_LIST attr_list_entry;
01258 int i;
01259 USHORT length;
01260
01261 DebugPrint("Allocated size = %I64u bytes.\n",size);
01262 if(size == 0){
01263 DebugPrint("Empty nonresident attribute list found.\n");
01264 return;
01265 }
01266
01267
01268 clusters_to_read = size / bytes_per_cluster;
01269
01270 if(size - clusters_to_read * bytes_per_cluster) clusters_to_read ++;
01271 cluster = (char *)winx_heap_alloc((SIZE_T)(bytes_per_cluster * clusters_to_read));
01272 if(!cluster){
01273 DebugPrint("Cannot allocate %I64u bytes of memory for AnalyseNonResidentAttributeList()!\n",
01274 bytes_per_cluster * clusters_to_read);
01275 out_of_memory_condition_counter ++;
01276 return;
01277 }
01278
01279
01280 current_cluster = cluster;
01281 for(block = pfn->blockmap; block != NULL; block = block->next_ptr){
01282
01283 for(i = 0; i < block->length; i++){
01284
01285 lsn = (block->lcn + i) * sectors_per_cluster;
01286 status = ReadSectors(lsn,current_cluster,(ULONG)bytes_per_cluster);
01287 if(!NT_SUCCESS(status)){
01288 DebugPrint("Cannot read the %I64u sector: %x!\n",
01289 lsn,(UINT)status);
01290 goto scan_done;
01291 }
01292 clusters_to_read --;
01293 if(clusters_to_read == 0){
01294
01295 if(i < (block->length - 1) || block->next_ptr != pfn->blockmap)
01296 DebugPrint("The attribute list has more clusters than expected.\n");
01297 goto analyze_list;
01298 }
01299 current_cluster += bytes_per_cluster;
01300 }
01301 if(block->next_ptr == pfn->blockmap) break;
01302 }
01303
01304 analyze_list:
01305 if(clusters_to_read){
01306 DebugPrint("The attribute list has less number of clusters than expected.\n");
01307 DebugPrint("Therefore it will be skipped, because anyway we don\'t know its exact size.\n");
01308 goto scan_done;
01309 }
01310
01311 DebugPrint("Attribute list analysis started...\n");
01312 attr_list_entry = (PATTRIBUTE_LIST)cluster;
01313
01314 while(TRUE){
01315 if( ((char *)attr_list_entry + sizeof(ATTRIBUTE_LIST) - sizeof(attr_list_entry->AlignmentOrReserved)) >
01316 ((char *)cluster + size) ) break;
01317 if(CheckForStopEvent()) break;
01318
01319 if(attr_list_entry->AttributeType == 0xffffffff) break;
01320 if(attr_list_entry->AttributeType == 0x0) break;
01321 if(attr_list_entry->Length == 0) break;
01322
01323 AnalyseAttributeFromAttributeList(attr_list_entry,pmfi);
01324
01325 length = attr_list_entry->Length;
01326 attr_list_entry = (PATTRIBUTE_LIST)((char *)attr_list_entry + length);
01327 }
01328 DebugPrint("Attribute list analysis completed.\n");
01329
01330 scan_done:
01331
01332 winx_heap_free(cluster);
01333 }
01334
01335
01336
01345 ULONGLONG ProcessMftSpace(PNTFS_DATA nd)
01346 {
01347 ULONGLONG start,len,mft_len = 0,mirror_size;
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360 DebugPrint("MFT part : start : length\n");
01361
01362
01363 start = nd->MftStartLcn.QuadPart;
01364 if(nd->BytesPerCluster)
01365 len = nd->MftValidDataLength.QuadPart / nd->BytesPerCluster;
01366 else
01367 len = 0;
01368 DebugPrint("$MFT :%I64u :%I64u\n",start,len);
01369 if(CheckBlock(start,len)){
01370
01371 RemarkBlock(start,len,MFT_ZONE_SPACE,SYSTEM_OR_FREE_SPACE);
01372 RemoveFreeSpaceBlock(start,len);
01373 mft_start = start; mft_end = start + len - 1;
01374 mft_len += len;
01375 }
01376
01377
01378 start = nd->MftZoneStart.QuadPart;
01379 len = nd->MftZoneEnd.QuadPart - nd->MftZoneStart.QuadPart + 1;
01380 DebugPrint("MFT Zone :%I64u :%I64u\n",start,len);
01381 if(CheckBlock(start,len)){
01382
01383 RemarkBlock(start,len,MFT_ZONE_SPACE,SYSTEM_OR_FREE_SPACE);
01384 RemoveFreeSpaceBlock(start,len);
01385 mftzone_start = start; mftzone_end = start + len - 1;
01386 }
01387
01388
01389 start = nd->Mft2StartLcn.QuadPart;
01390 len = 1;
01391 mirror_size = nd->BytesPerFileRecordSegment * 4;
01392 if(nd->BytesPerCluster && mirror_size > nd->BytesPerCluster){
01393 len = mirror_size / nd->BytesPerCluster;
01394 if(mirror_size - len * nd->BytesPerCluster)
01395 len ++;
01396 }
01397 DebugPrint("$MFTMirror :%I64u :%I64u\n",start,len);
01398 if(CheckBlock(start,len)){
01399
01400 RemarkBlock(start,len,MFT_ZONE_SPACE,SYSTEM_OR_FREE_SPACE);
01401 RemoveFreeSpaceBlock(start,len);
01402 mftmirr_start = start; mftmirr_end = start + len - 1;
01403 }
01404
01405 return mft_len;
01406 }
01407
01408
01409
01410
01411
01412
01425 void ProcessRun(WCHAR *full_path,PMY_FILE_INFORMATION pmfi,
01426 PFILENAME pfn,ULONGLONG vcn,ULONGLONG length,ULONGLONG lcn)
01427 {
01428 PBLOCKMAP block, prev_block = NULL;
01429
01430
01431
01432
01433
01434 (void)pmfi;
01435
01436
01437 if(pfn->blockmap) prev_block = pfn->blockmap->prev_ptr;
01438 block = (PBLOCKMAP)winx_list_insert_item((list_entry **)&pfn->blockmap,(list_entry *)prev_block,sizeof(BLOCKMAP));
01439 if(!block){
01440 DebugPrint("Cannot allocate %u bytes of memory for ProcessRun()!\n",sizeof(BLOCKMAP));
01441 out_of_memory_condition_counter ++;
01442 return;
01443 }
01444
01445 block->vcn = vcn;
01446 block->length = length;
01447 block->lcn = lcn;
01448
01449 pfn->n_fragments ++;
01450 pfn->clusters_total += block->length;
01451
01452
01453
01454
01455 if(block != pfn->blockmap && 01456 block->lcn != (block->prev_ptr->lcn + block->prev_ptr->length))
01457 pfn->is_fragm = TRUE;
01458 }
01459
01469 PFILENAME FindFileListEntryForTheAttribute(WCHAR *full_path,PMY_FILE_INFORMATION pmfi)
01470 {
01471 PFILENAME pfn;
01472
01473
01474 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01475
01476
01477
01478
01479 if(MftScanDirection == MFT_SCAN_RTL){
01480 if(pfn->BaseMftId > pmfi->BaseMftId) break;
01481 } else {
01482 if(pfn->BaseMftId < pmfi->BaseMftId) break;
01483 }
01484 if(!wcscmp(pfn->name.Buffer,full_path) && 01485 (pfn->ParentDirectoryMftId == pmfi->ParentDirectoryMftId) && 01486 (pfn->BaseMftId == pmfi->BaseMftId))
01487 return pfn;
01488
01489 if(pfn->next_ptr == filelist) break;
01490 }
01491
01492 pfn = (PFILENAME)winx_list_insert_item((list_entry **)(void *)&filelist,NULL,sizeof(FILENAME));
01493 if(pfn == NULL){
01494 DebugPrint("Cannot allocate %u bytes of memory for FindFileListEntryForTheAttribute()!\n",sizeof(FILENAME));
01495 out_of_memory_condition_counter ++;
01496 return NULL;
01497 }
01498
01499
01500 if(!RtlCreateUnicodeString(&pfn->name,full_path)){
01501 DebugPrint("Not enough memory for pfn->name initialization!\n");
01502 out_of_memory_condition_counter ++;
01503 winx_list_remove_item((list_entry **)(void *)&filelist,(list_entry *)pfn);
01504 return NULL;
01505 }
01506 pfn->blockmap = NULL;
01507 pfn->BaseMftId = pmfi->BaseMftId;
01508 pfn->ParentDirectoryMftId = pmfi->ParentDirectoryMftId;
01509 pfn->PathBuilt = FALSE;
01510 pfn->n_fragments = 0;
01511 pfn->clusters_total = 0;
01512 pfn->is_fragm = FALSE;
01513 pfn->is_compressed = FALSE;
01514 pfn->is_dirty = TRUE;
01515 pfn->is_filtered = FALSE;
01516 return pfn;
01517 }
01518
01525 void UpdateClusterMapAndStatistics(PMY_FILE_INFORMATION pmfi)
01526 {
01527 PFILENAME pfn;
01528 ULONGLONG filesize;
01529
01530
01531 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01532
01533 if(pfn->is_dirty == FALSE) break;
01534
01535 pfn->is_dirty = FALSE;
01536
01537
01538
01539
01540
01541
01542
01543
01544 pfn->is_dir = pmfi->IsDirectory;
01545
01546
01547
01548
01549 if((pmfi->Flags & FILE_ATTRIBUTE_REPARSE_POINT) || pmfi->IsReparsePoint){
01550 DebugPrint("Reparse point found %ws\n",pfn->name.Buffer);
01551 pfn->is_reparse_point = TRUE;
01552 } else pfn->is_reparse_point = FALSE;
01553
01554 filesize = pfn->clusters_total * bytes_per_cluster;
01555 if(sizelimit && filesize > sizelimit) pfn->is_overlimit = TRUE;
01556 else pfn->is_overlimit = FALSE;
01557
01558 CHECK_FOR_FRAGLIMIT(pfn);
01559
01560 if(TemporaryStuffDetected(pmfi)) pfn->is_filtered = TRUE;
01561
01562 if(pmfi->Flags & FILE_ATTRIBUTE_SPARSE_FILE)
01563 DebugPrint("Sparse file found %ws\n",pfn->name.Buffer);
01564
01565 if(pmfi->Flags & FILE_ATTRIBUTE_ENCRYPTED){
01566 DebugPrint2("Encrypted file found %ws\n",pfn->name.Buffer);
01567 }
01568
01569
01570
01571 Stat.filecounter ++;
01572 if(pfn->is_dir) Stat.dircounter ++;
01573 if(pfn->is_compressed) Stat.compressedcounter ++;
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584 Stat.processed_clusters += pfn->clusters_total;
01585
01586 if(pfn->next_ptr == filelist) break;
01587 }
01588 }
01589
01597 BOOLEAN TemporaryStuffDetected(PMY_FILE_INFORMATION pmfi)
01598 {
01599
01600 if(pmfi->Flags & FILE_ATTRIBUTE_TEMPORARY){
01601 DebugPrint2("-Ultradfg- Temporary file found %ws\n",pmfi->Name);
01602 return TRUE;
01603 }
01604 return FALSE;
01605 }
01606
01607
01615 BOOLEAN UnwantedStuffDetected(PFILENAME pfn)
01616 {
01617 UNICODE_STRING us;
01618
01619
01620 if(!RtlCreateUnicodeString(&us,pfn->name.Buffer)){
01621 DebugPrint("Cannot allocate memory for UnwantedStuffDetected()!\n");
01622 out_of_memory_condition_counter ++;
01623 return FALSE;
01624 }
01625 (void)_wcslwr(us.Buffer);
01626
01627 if(in_filter.buffer){
01628 if(!IsStringInFilter(us.Buffer,&in_filter)){
01629 RtlFreeUnicodeString(&us); return TRUE;
01630 }
01631 }
01632
01633 if(ex_filter.buffer){
01634 if(IsStringInFilter(us.Buffer,&ex_filter)){
01635 RtlFreeUnicodeString(&us); return TRUE;
01636 }
01637 }
01638 RtlFreeUnicodeString(&us);
01639
01640 return FALSE;
01641 }
01642
01643 PMY_FILE_ENTRY mf = NULL;
01644 ULONG n_entries;
01645 BOOLEAN mf_allocated = FALSE;
01646
01651 void BuildPaths(void)
01652 {
01653 ULONGLONG tm, time;
01654 PFILENAME pfn;
01655 ULONG i;
01656
01657 DebugPrint("BuildPaths() started...\n");
01658 tm = winx_xtime();
01659
01660
01661 mf_allocated = FALSE;
01662
01663
01664 n_entries = 0;
01665 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01666 n_entries++;
01667 if(pfn->next_ptr == filelist) break;
01668 }
01669
01670 if(n_entries){
01671 mf = (PMY_FILE_ENTRY)winx_heap_alloc(n_entries * sizeof(MY_FILE_ENTRY));
01672 if(mf != NULL) mf_allocated = TRUE;
01673 else DebugPrint("Cannot allocate %u bytes of memory for mf array!\n",
01674 n_entries * sizeof(MY_FILE_ENTRY));
01675 }
01676 if(mf_allocated){
01677
01678 i = 0;
01679 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01680 mf[i].mft_id = pfn->BaseMftId;
01681 mf[i].pfn = pfn;
01682 if(i == (n_entries - 1)){
01683 if(pfn->next_ptr != filelist)
01684 DebugPrint("BuildPaths(): ???\n");
01685 break;
01686 }
01687 i++;
01688 if(pfn->next_ptr == filelist) break;
01689 }
01690 DebugPrint("Fast binary search will be used.\n");
01691 } else {
01692 DebugPrint("Slow linear search will be used.\n");
01693 }
01694
01695 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01696 BuildPath2(pfn);
01697 if(UnwantedStuffDetected(pfn)) pfn->is_filtered = TRUE;
01698 MarkFileSpace(pfn,SYSTEM_OR_MFT_ZONE_SPACE);
01699
01700 if(pfn->is_fragm && !pfn->is_reparse_point &&
01701 ((!pfn->is_filtered && !pfn->is_overlimit) || optimize_flag)
01702 ){
01703 Stat.fragmfilecounter ++;
01704 Stat.fragmcounter += pfn->n_fragments;
01705 } else {
01706 Stat.fragmcounter ++;
01707 }
01708 if(pfn->next_ptr == filelist) break;
01709 }
01710
01711
01712 if(mf_allocated) winx_heap_free(mf);
01713 time = winx_xtime() - tm;
01714 DebugPrint("BuildPaths() completed in %I64u ms.\n",time);
01715 }
01716
01722 void BuildPath2(PFILENAME pfn)
01723 {
01724 WCHAR *buffer1;
01725 WCHAR *buffer2;
01726 ULONG offset;
01727 ULONGLONG mft_id,parent_mft_id;
01728 ULONG name_length;
01729 WCHAR header[] = L"\\??\\A:";
01730 BOOLEAN FullPathRetrieved = FALSE;
01731 UNICODE_STRING us;
01732
01733
01734 if(pfn->name.Buffer[0] == 0){
01735 DebugPrint("BuildPath2: Invalid entry found: file has no name!\n");
01736 DebugPrint("BuildPath2: MFT ID = %I64u\n",pfn->BaseMftId);
01737 return;
01738 }
01739
01740
01741 buffer1 = (WCHAR *)winx_heap_alloc((MAX_NTFS_PATH) * sizeof(short));
01742 if(!buffer1){
01743 DebugPrint("BuildPath2(): cannot allocate memory for buffer1\n");
01744 out_of_memory_condition_counter ++;
01745 return;
01746 }
01747 buffer2 = (WCHAR *)winx_heap_alloc((MAX_NTFS_PATH) * sizeof(short));
01748 if(!buffer2){
01749 DebugPrint("BuildPath2(): cannot allocate memory for buffer2\n");
01750 out_of_memory_condition_counter ++;
01751 winx_heap_free(buffer1);
01752 return;
01753 }
01754
01755
01756 offset = MAX_NTFS_PATH - 1;
01757 buffer1[offset] = 0;
01758 offset --;
01759
01760
01761 name_length = wcslen(pfn->name.Buffer);
01762 if(offset < (name_length - 1)){
01763 DebugPrint("BuildPath2(): %ws filename is too long (%u characters)\n",
01764 pfn->name.Buffer,name_length);
01765 winx_heap_free(buffer1);
01766 winx_heap_free(buffer2);
01767 return;
01768 }
01769
01770 offset -= (name_length - 1);
01771 (void)wcsncpy(buffer1 + offset,pfn->name.Buffer,name_length);
01772
01773 if(offset == 0) goto path_is_too_long;
01774 offset --;
01775
01776
01777 buffer1[offset] = '\\';
01778
01779 if(offset == 0) goto path_is_too_long;
01780 offset --;
01781
01782 if(offset == 0) goto path_is_too_long;
01783
01784 parent_mft_id = pfn->ParentDirectoryMftId;
01785 while(parent_mft_id != FILE_root){
01786 if(CheckForStopEvent()) goto build_path_done;
01787 mft_id = parent_mft_id;
01788 FullPathRetrieved = GetFileNameAndParentMftId(mft_id,&parent_mft_id,buffer2,MAX_NTFS_PATH);
01789 if(buffer2[0] == 0){
01790 DebugPrint("BuildPath2(): cannot retrieve parent directory name!\n");
01791 goto build_path_done;
01792 }
01793
01794
01795 name_length = wcslen(buffer2);
01796 if(offset < (name_length - 1)) goto path_is_too_long;
01797 offset -= (name_length - 1);
01798 (void)wcsncpy(buffer1 + offset,buffer2,name_length);
01799
01800 if(FullPathRetrieved) goto update_filename;
01801
01802 if(offset == 0) goto path_is_too_long;
01803 offset --;
01804
01805
01806 buffer1[offset] = '\\';
01807
01808 if(offset == 0) goto path_is_too_long;
01809 offset --;
01810
01811 if(offset == 0) goto path_is_too_long;
01812 }
01813
01814
01815
01816
01817
01818 if(offset == ((MAX_NTFS_PATH - 1) - 3) && buffer1[offset + 1] == '\\'
01819 && buffer1[offset + 2] == '.'){
01820 DebugPrint("Root directory detected, its trailing dot will be removed.\n");
01821 buffer1[offset + 2] = 0;
01822 }
01823
01824
01825 header[4] = volume_letter;
01826 name_length = wcslen(header);
01827 if(offset < (name_length - 1)) goto path_is_too_long;
01828 offset -= (name_length - 1);
01829 (void)wcsncpy(buffer1 + offset,header,name_length);
01830
01831 update_filename:
01832
01833
01834
01835 if(!RtlCreateUnicodeString(&us,buffer1 + offset)){
01836 DebugPrint("Cannot allocate memory for BuildPath2()!\n");
01837 out_of_memory_condition_counter ++;
01838 } else {
01839 RtlFreeUnicodeString(&(pfn->name));
01840 pfn->name.Buffer = us.Buffer;
01841 pfn->name.Length = us.Length;
01842 pfn->name.MaximumLength = us.MaximumLength;
01843 }
01844 pfn->PathBuilt = TRUE;
01845
01846 #ifdef DETAILED_LOGGING
01847 DebugPrint("FULL PATH = %ws\n",pfn->name.Buffer);
01848 #endif
01849
01850 build_path_done:
01851 winx_heap_free(buffer1);
01852 winx_heap_free(buffer2);
01853 return;
01854
01855 path_is_too_long:
01856 DebugPrint("BuildPath2(): path is too long: %ws\n",buffer1);
01857 winx_heap_free(buffer1);
01858 winx_heap_free(buffer2);
01859 }
01860
01875 BOOLEAN GetFileNameAndParentMftId(ULONGLONG mft_id,ULONGLONG *parent_mft_id,WCHAR *buffer,ULONG length)
01876 {
01877 PFILENAME pfn;
01878 BOOLEAN FullPathRetrieved = FALSE;
01879
01880
01881 buffer[0] = 0;
01882 *parent_mft_id = FILE_root;
01883
01884
01885 pfn = FindDirectoryByMftId(mft_id);
01886
01887 if(pfn == NULL){
01888 DebugPrint("%I64u directory not found!\n",mft_id);
01889 return FullPathRetrieved;
01890 }
01891
01892
01893 *parent_mft_id = pfn->ParentDirectoryMftId;
01894 (void)wcsncpy(buffer,pfn->name.Buffer,length);
01895 buffer[length-1] = 0;
01896 FullPathRetrieved = pfn->PathBuilt;
01897
01898 if(buffer[0] == 0){
01899 DebugPrint("GetFileNameAndParentMftId: Invalid entry found: file has no name!\n");
01900 DebugPrint("GetFileNameAndParentMftId: MFT ID = %I64u\n",mft_id);
01901 }
01902
01903 return FullPathRetrieved;
01904 }
01905
01911 void AddResidentDirectoryToFileList(PMY_FILE_INFORMATION pmfi)
01912 {
01913 PFILENAME pfn;
01914
01915 if(pmfi->Name[0] == 0){
01916 DebugPrint("AddResidentDirectoryToFileList: Invalid entry found: file has no name!\n");
01917 DebugPrint("AddResidentDirectoryToFileList: MFT ID = %I64u\n",pmfi->BaseMftId);
01918 return;
01919 }
01920
01921 pfn = (PFILENAME)winx_list_insert_item((list_entry **)(void *)&filelist,NULL,sizeof(FILENAME));
01922 if(pfn == NULL){
01923 DebugPrint("Cannot allocate %u bytes of memory for AddResidentDirectoryToFileList()!\n",sizeof(FILENAME));
01924 out_of_memory_condition_counter ++;
01925 return;
01926 }
01927
01928
01929 if(!RtlCreateUnicodeString(&pfn->name,pmfi->Name)){
01930 DebugPrint("AddResidentDirectoryToFileList():\n");
01931 DebugPrint("no enough memory for pfn->name initialization!\n");
01932 out_of_memory_condition_counter ++;
01933 winx_list_remove_item((list_entry **)(void *)&filelist,(list_entry *)pfn);
01934 return;
01935 }
01936 pfn->blockmap = NULL;
01937 pfn->BaseMftId = pmfi->BaseMftId;
01938 pfn->ParentDirectoryMftId = pmfi->ParentDirectoryMftId;
01939 pfn->PathBuilt = FALSE;
01940 pfn->n_fragments = 0;
01941 pfn->clusters_total = 0;
01942 pfn->is_fragm = FALSE;
01943 pfn->is_compressed = FALSE;
01944 pfn->is_dir = TRUE;
01945 pfn->is_reparse_point = pmfi->IsReparsePoint;
01946 pfn->is_overlimit = FALSE;
01947 pfn->is_filtered = TRUE;
01948 pfn->is_dirty = TRUE;
01949 }
01950
01957 PFILENAME FindDirectoryByMftId(ULONGLONG mft_id)
01958 {
01959 PFILENAME pfn;
01960 ULONG lim, i, k;
01961 signed long m;
01962 BOOLEAN ascending_order;
01963
01964 if(mf_allocated == FALSE){
01965 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){
01966 if(pfn->BaseMftId == mft_id){
01967 if(wcsstr(pfn->name.Buffer,L":$") == NULL)
01968 return pfn;
01969 }
01970 if(pfn->next_ptr == filelist) break;
01971 }
01972 return NULL;
01973 } else {
01974
01975 ascending_order = (MftScanDirection == MFT_SCAN_RTL) ? TRUE : FALSE;
01976 i = 0;
01977 for(lim = n_entries; lim != 0; lim >>= 1){
01978 k = i + (lim >> 1);
01979 if(mf[k].mft_id == mft_id){
01980
01981 for(m = k; m >= 0; m --){
01982 if(mf[m].mft_id != mft_id) break;
01983 }
01984 for(m = m + 1; (unsigned long)(m) < n_entries; m ++){
01985 if(mf[m].mft_id != mft_id) break;
01986 if(wcsstr(mf[m].pfn->name.Buffer,L":$") == NULL)
01987 return mf[m].pfn;
01988 }
01989 DebugPrint("FindDirectoryByMftId - Exit 1\n");
01990 return NULL;
01991 }
01992 if(ascending_order){
01993 if(mft_id > mf[k].mft_id){
01994 i = k + 1; lim --;
01995 }
01996 } else {
01997 if(mft_id < mf[k].mft_id){
01998 i = k + 1; lim --;
01999 }
02000 }
02001 }
02002 DebugPrint("FindDirectoryByMftId - Exit 2\n");
02003 return NULL;
02004 }
02005 }
02006
02019 NTSTATUS ReadSectors(ULONGLONG lsn,PVOID buffer,ULONG length)
02020 {
02021 IO_STATUS_BLOCK ioStatus;
02022 LARGE_INTEGER offset;
02023 NTSTATUS Status;
02024 ULONGLONG tm, time;
02025
02026 offset.QuadPart = lsn * bytes_per_sector;
02027 Status = NtReadFile(winx_fileno(fVolume),NULL,NULL,NULL,&ioStatus,buffer,length,&offset,NULL);
02028 if(NT_SUCCESS(Status)){
02029 DebugPrint("ReadSectors waiting started...\n");
02030 tm = winx_xtime();
02031 Status = NtWaitForSingleObject(winx_fileno(fVolume),FALSE,NULL);
02032 time = winx_xtime() - tm;
02033 DebugPrint("ReadSectors waiting completed in %I64u ms.\n", time);
02034 if(NT_SUCCESS(Status)) Status = ioStatus.Status;
02035 }
02036
02037 return Status;
02038 }
02039