![]() |
UltraDefrag Engine Architecture - Reference Manual - Guides |
|
00001 /* 00002 * UltraDefrag - powerful defragmentation tool for Windows NT. 00003 * Copyright (c) 2007-2010 by Dmitri Arkhangelski (dmitriar@gmail.com). 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 */ 00019 00027 /* 00028 * NOTE: the following file systems will be analysed 00029 * through reading their structures directly from disk 00030 * and interpreting them: NTFS, FAT12, FAT16, FAT32. 00031 * This cool idea was suggested by Parvez Reza (parvez_ku_00@yahoo.com). 00032 * 00033 * UDF filesystem is missing in this list, because its 00034 * standard is too complicated (http://www.osta.org/specs/). 00035 * Therefore it will be analysed through standard Windows API. 00036 * 00037 * - Why a special code? 00038 * - It works faster: 00039 * * NTFS ultra fast scan may be 25 times faster than universal scan 00040 * * FAT16 scan may be 40% faster. 00041 * 00042 * P.S.: We decided to avoid direct FAT scan in this driver, 00043 * because it works slower than the universal scan. Due to the 00044 * file system caching Windows feature. 00045 */ 00046 00047 #include "globals.h" 00048 00058 int Analyze(char *volume_name) 00059 { 00060 unsigned short path[] = L"\\??\\A:\\"; 00061 NTSTATUS Status; 00062 ULONGLONG tm, time; 00063 ULONG pass_number; 00064 int error_code; 00065 00066 DebugPrint("----- Analyze of %s: -----\n",volume_name); 00067 00068 /* initialize cluster map */ 00069 MarkAllSpaceAsFree0(); 00070 00071 /* reset file lists */ 00072 DestroyLists(); 00073 00074 /* reset statistics */ 00075 pass_number = Stat.pass_number; 00076 memset(&Stat,0,sizeof(STATISTIC)); 00077 Stat.current_operation = 'A'; 00078 Stat.pass_number = pass_number; 00079 00080 /* reset coordinates of mft zones */ 00081 mft_start = 0, mft_end = 0, mftzone_start = 0, mftzone_end = 0; 00082 mftmirr_start = 0, mftmirr_end = 0; 00083 00084 /* open the volume */ 00085 error_code = OpenVolume(volume_name); 00086 if(error_code < 0) return error_code; 00087 00088 /* flush all file buffers */ 00089 if(initial_analysis){ 00090 DebugPrint("Flush all file buffers!\n"); 00091 FlushAllFileBuffers(volume_name); 00092 } 00093 00094 /* get drive geometry */ 00095 error_code = GetDriveGeometry(volume_name); 00096 if(error_code < 0) return error_code; 00097 00098 /* update map representation */ 00099 MarkAllSpaceAsSystem1(); 00100 00101 /* define file system */ 00102 CheckForNtfsPartition(); 00103 00104 /* update progress counters */ 00105 tm = _rdtsc(); 00106 Stat.clusters_to_process = clusters_total; 00107 Stat.processed_clusters = 0; 00108 00109 /* scan volume for free space areas */ 00110 Status = FillFreeSpaceMap(); 00111 if(!NT_SUCCESS(Status)){ 00112 DebugPrintEx(Status,"FillFreeSpaceMap() failed"); 00113 if(Status == STATUS_NO_MEMORY) return UDEFRAG_NO_MEM; 00114 return (-1); 00115 } 00116 //DebugPrint("FillFreeSpaceMap() time: %I64u mln.\n",(_rdtsc() - tm) / 1000000); 00117 00118 if(CheckForStopEvent()) return 0; 00119 00120 switch(partition_type){ 00121 case NTFS_PARTITION: 00122 /* 00123 * ScanMFT() causes BSOD on NT 4.0, even in user mode! 00124 * It seems that NTFS driver is imperfect in this system 00125 * and ScanMFT() breaks something inside it. 00126 * Sometimes BSOD appears during an analysis after volume optimization, 00127 * sometimes it appears immediately during the first analysis. 00128 * Examples: 00129 * 1. kmd compact ntfs nt4 -> BSOD 0xa (0x48, 0xFF, 0x0, 0x80101D5D) 00130 * immediately after the last analysis 00131 * 2. user mode - optimize - BSOD during the second analysis 00132 * 0x50 (0xB51CA820,0,0,2) or 0x1E (0xC...5,0x8013A7B6,0,0x20) 00133 * 3. kmd - nt4 - gui - optimize - chkdsk /F for ntfs - bsod 00134 */ 00135 /*if(nt4_system){ 00136 DebugPrint("Ultrafast NTFS scan is not avilable on NT 4.0\n"); 00137 DebugPrint("due to ntfs.sys driver imperfectness.\n"); 00138 goto universal_scan; 00139 }*/ 00140 (void)ScanMFT(); 00141 break; 00142 /*case FAT12_PARTITION: 00143 (void)ScanFat12Partition(); 00144 break; 00145 case FAT16_PARTITION: 00146 (void)ScanFat16Partition(); 00147 break; 00148 case FAT32_PARTITION: 00149 (void)ScanFat32Partition(); 00150 break;*/ 00151 default: /* UDF, Ext2 and so on... */ 00152 /*universal_scan:*/ 00153 /* Find files */ 00154 tm = _rdtsc(); 00155 path[4] = (short)volume_letter; 00156 error_code = FindFiles(path); 00157 if(error_code < 0){ 00158 DebugPrint("FindFiles() failed!\n"); 00159 return error_code; 00160 } 00161 time = _rdtsc() - tm; 00162 DebugPrint("An universal scan needs %I64u ms\n",time); 00163 } 00164 00165 DebugPrint("Files found: %u\n",Stat.filecounter); 00166 DebugPrint("Fragmented files: %u\n",Stat.fragmfilecounter); 00167 00168 /* remark space belonging to well known locked files as system */ 00169 RemarkWellKnownLockedFiles(); 00170 00171 GenerateFragmentedFilesList(); 00172 return 0; 00173 } 00174 00188 BOOLEAN IsFileLocked(PFILENAME pfn) 00189 { 00190 NTSTATUS Status; 00191 HANDLE hFile; 00192 00193 /* is the file already checked? */ 00194 if(pfn->blockmap == NULL) return TRUE; 00195 00196 /* check the file */ 00197 Status = OpenTheFile(pfn,&hFile); 00198 if(Status == STATUS_SUCCESS){ 00199 NtCloseSafe(hFile); 00200 return FALSE; 00201 } 00202 00203 DebugPrintEx(Status,"Cannot open %ws",pfn->name.Buffer); 00204 00205 /* locked file found, remark space belonging to it! */ 00206 RemarkFileSpaceAsSystem(pfn); 00207 00208 /* file is locked by other application, so its state is unknown */ 00209 DeleteBlockmap(pfn); 00210 return TRUE; 00211 } 00212 00213 /* 00214 * Minimal name lengths! 00215 * Lowercase! 00216 */ 00217 #if 0 00218 short *known_locked_files[] = { 00219 L"pagefile.sys", 00220 L"hiberfil.sys", 00221 L"ntuser.dat", 00222 /*L"system vol",*/ /* system volume information gives a lot of false detection */ 00223 /*L"em32\\config",*/ /* the same cause */ 00224 NULL 00225 }; 00226 #endif 00227 00234 BOOLEAN IsMft(PFILENAME pfn) 00235 { 00236 short mft_path[] = L"\\??\\C:\\$MFT"; 00237 UNICODE_STRING us; 00238 BOOLEAN result; 00239 00240 if(pfn->name.Length < 9 * sizeof(short)) /* ensure that we have at least \??\X:\$x */ 00241 return FALSE; 00242 if(pfn->name.Buffer[7] != '$') 00243 return FALSE; 00244 00245 mft_path[4] = (short)volume_letter; 00246 (void)_wcslwr(mft_path); 00247 00248 if(!RtlCreateUnicodeString(&us,pfn->name.Buffer)){ 00249 DebugPrint("Cannot allocate memory for IsMft()!\n"); 00250 out_of_memory_condition_counter ++; 00251 return FALSE; 00252 } 00253 (void)_wcslwr(us.Buffer); 00254 00255 result = (wcscmp(us.Buffer,mft_path) == 0) ? TRUE : FALSE; 00256 00257 RtlFreeUnicodeString(&us); 00258 return result; 00259 } 00260 00268 BOOLEAN IsWellKnownSystemFile(PFILENAME pfn) 00269 { 00270 UNICODE_STRING us; 00271 /*int i;*/ 00272 short *pos; 00273 short config_sign[] = L"\\system32\\config\\"; 00274 00275 if(!RtlCreateUnicodeString(&us,pfn->name.Buffer)){ 00276 DebugPrint("Cannot allocate memory for IsWellKnownSystemFile()!\n"); 00277 out_of_memory_condition_counter ++; 00278 return FALSE; 00279 } 00280 (void)_wcslwr(us.Buffer); 00281 00282 /* search for NTFS internal files */ 00283 if(us.Length >= 9 * sizeof(short)){ /* to ensure that we have at least \??\X:\$x */ 00284 /* skip \??\X:\$mft */ 00285 if(us.Buffer[7] == '$' && us.Buffer[8] == 'm'){ 00286 if(IsMft(pfn)) goto not_found; 00287 } 00288 if(us.Buffer[7] == '$') goto found; 00289 } 00290 00291 /* search for big files usually locked by Windows */ 00292 /*for(i = 0;; i++){ 00293 if(known_locked_files[i] == NULL) goto not_found; 00294 if(wcsstr(us.Buffer,known_locked_files[i])) goto found; 00295 }*/ 00296 if(wcsstr(us.Buffer,L"pagefile.sys")) goto found; 00297 if(wcsstr(us.Buffer,L"hiberfil.sys")) goto found; 00298 if(wcsstr(us.Buffer,L"ntuser.dat")) goto found; 00299 pos = wcsstr(us.Buffer,config_sign); 00300 if(pos){ 00301 /* skip sub directories */ 00302 pos += (sizeof(config_sign) / sizeof(short)) - 1; 00303 if(!wcschr(pos,'\\') && !pfn->is_dir) goto found; 00304 } 00305 00306 /* 00307 * Other system files will be detected during the defragmentation, 00308 * because otherwise this will take a lot of time. 00309 */ 00310 goto not_found; 00311 00312 found: 00313 RtlFreeUnicodeString(&us); 00314 return TRUE; 00315 00316 not_found: 00317 RtlFreeUnicodeString(&us); 00318 return FALSE; 00319 } 00320 00326 void RemarkWellKnownLockedFiles(void) 00327 { 00328 ULONGLONG tm, time; 00329 PFILENAME pfn; 00330 NTSTATUS Status; 00331 HANDLE hFile; 00332 00333 DebugPrint("Well known locked files search started...\n"); 00334 tm = _rdtsc(); 00335 00336 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){ 00337 if(pfn->is_reparse_point == FALSE && pfn->blockmap){ 00338 if(IsWellKnownSystemFile(pfn)){ 00339 Status = OpenTheFile(pfn,&hFile); 00340 if(Status == STATUS_SUCCESS){ 00341 NtCloseSafe(hFile); 00342 /* possibility of this case must be reduced */ 00343 DebugPrint("False detection %ws!\n",pfn->name.Buffer); 00344 } else { 00345 DebugPrintEx(Status,"Cannot open %ws",pfn->name.Buffer); 00346 00347 /* locked file found, remark space belonging to it! */ 00348 RemarkFileSpaceAsSystem(pfn); 00349 00350 /* file is locked by other application, so its state is unknown */ 00351 DeleteBlockmap(pfn); 00352 } 00353 } 00354 } 00355 if(pfn->next_ptr == filelist) break; 00356 } 00357 00358 time = _rdtsc() - tm; 00359 DebugPrint("Well known locked files search completed in %I64u ms.\n", time); 00360 } 00361 00362 #if 0 00363 00368 void CheckAllFragmentedFiles(void) 00369 { 00370 ULONGLONG tm, time; 00371 PFRAGMENTED pf; 00372 00373 DebugPrint("+-------------------------------------------------------+\n"); 00374 DebugPrint("| Fragmented files checking started... |\n"); 00375 DebugPrint("+-------------------------------------------------------+\n"); 00376 DebugPrint("UltraDefrag will try to open them to ensure that they are not locked.\n"); 00377 DebugPrint("This may take few minutes if there are many fragmented files on the disk.\n"); 00378 DebugPrint("\n"); 00379 tm = _rdtsc(); 00380 00381 for(pf = fragmfileslist; pf != NULL; pf = pf->next_ptr){ 00382 (void)IsFileLocked(pf->pfn); 00383 if(pf->next_ptr == fragmfileslist) break; 00384 } 00385 00386 time = _rdtsc() - tm; 00387 DebugPrint("---------------------------------------------------------\n"); 00388 DebugPrint("Fragmented files checking completed in %I64u ms.\n", time); 00389 DebugPrint("---------------------------------------------------------\n"); 00390 } 00391 00397 void CheckAllFiles(void) 00398 { 00399 ULONGLONG tm, time; 00400 PFILENAME pfn; 00401 00402 DebugPrint("+-------------------------------------------------------+\n"); 00403 DebugPrint("| Files checking started... |\n"); 00404 DebugPrint("+-------------------------------------------------------+\n"); 00405 DebugPrint("UltraDefrag will try to open them to ensure that they are not locked.\n"); 00406 DebugPrint("This may take few minutes if there are many files on the disk.\n"); 00407 DebugPrint("\n"); 00408 tm = _rdtsc(); 00409 00410 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){ 00411 (void)IsFileLocked(pfn); 00412 if(pfn->next_ptr == filelist) break; 00413 } 00414 00415 time = _rdtsc() - tm; 00416 DebugPrint("---------------------------------------------------------\n"); 00417 DebugPrint("Files checking completed in %I64u ms.\n", time); 00418 DebugPrint("---------------------------------------------------------\n"); 00419 } 00420 #endif 00421 00425 void GenerateFragmentedFilesList(void) 00426 { 00427 PFILENAME pfn; 00428 00429 for(pfn = filelist; pfn != NULL; pfn = pfn->next_ptr){ 00430 if(pfn->is_fragm && /* !pfn->is_filtered && */!pfn->is_reparse_point) 00431 AddFileToFragmented(pfn); 00432 if(pfn->next_ptr == filelist) break; 00433 } 00434 } 00435 00443 ULONGLONG _rdtsc(void) 00444 { 00445 return _rdtsc_1() / 1000 / 1000; 00446 } 00447 00455 ULONGLONG _rdtsc_1(void) 00456 { 00457 NTSTATUS Status; 00458 LARGE_INTEGER frequency; 00459 LARGE_INTEGER counter; 00460 00461 Status = NtQueryPerformanceCounter(&counter,&frequency); 00462 if(!NT_SUCCESS(Status)){ 00463 DebugPrint("NtQueryPerformanceCounter() failed: %x!\n",(UINT)Status); 00464 return 0; 00465 } 00466 if(!frequency.QuadPart){ 00467 DebugPrint("Your hardware has no support for High Resolution timer!\n"); 00468 return 0; 00469 } 00470 return ((1000 * 1000 * 1000) / frequency.QuadPart) * counter.QuadPart; 00471 } 00472