![]() |
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 #include "globals.h" 00028 00037 NTSTATUS OpenTheFile(PFILENAME pfn,HANDLE *phFile) 00038 { 00039 OBJECT_ATTRIBUTES ObjectAttributes; 00040 IO_STATUS_BLOCK ioStatus; 00041 ULONG flags = FILE_SYNCHRONOUS_IO_NONALERT; 00042 00043 if(!pfn || !phFile) return STATUS_INVALID_PARAMETER; 00044 00045 if(pfn->is_dir) flags |= FILE_OPEN_FOR_BACKUP_INTENT; 00046 else flags |= FILE_NO_INTERMEDIATE_BUFFERING; 00047 00048 InitializeObjectAttributes(&ObjectAttributes,&pfn->name,0,NULL,NULL); 00049 return NtCreateFile(phFile,FILE_GENERIC_READ | SYNCHRONIZE,&ObjectAttributes,&ioStatus, 00050 NULL,0,FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_OPEN,flags, 00051 NULL,0); 00052 } 00053 00067 BOOLEAN DumpFile(PFILENAME pfn) 00068 { 00069 ULONGLONG *FileMap; 00070 IO_STATUS_BLOCK ioStatus; 00071 PGET_RETRIEVAL_DESCRIPTOR fileMappings; 00072 NTSTATUS Status; 00073 HANDLE hFile; 00074 int i; 00075 long counter; 00076 #define MAX_COUNTER 1000 00077 PBLOCKMAP block = NULL; 00078 ULONGLONG startVcn; 00079 00080 /* Data initialization */ 00081 pfn->clusters_total = pfn->n_fragments = 0; 00082 pfn->is_fragm = FALSE; 00083 pfn->blockmap = NULL; 00084 00085 /* Open the file */ 00086 Status = OpenTheFile(pfn,&hFile); 00087 if(Status != STATUS_SUCCESS){ 00088 DebugPrint("System file found: %ws: %x\n",pfn->name.Buffer,(UINT)Status); 00089 return FALSE; /* File has unknown state! */ 00090 } 00091 00092 /* allocate memory */ 00093 FileMap = winx_heap_alloc(FILEMAPSIZE * sizeof(ULONGLONG)); 00094 if(FileMap == NULL){ 00095 DebugPrint("Cannot allocate memory for DumpFile()!\n"); 00096 out_of_memory_condition_counter ++; 00097 return FALSE; 00098 } 00099 00100 /* Start dumping the mapping information. Go until we hit the end of the file. */ 00101 startVcn = 0; 00102 fileMappings = (PGET_RETRIEVAL_DESCRIPTOR)(FileMap); 00103 counter = 0; 00104 do { 00105 RtlZeroMemory(fileMappings,FILEMAPSIZE * sizeof(ULONGLONG)); 00106 Status = NtFsControlFile(hFile, NULL, NULL, 0, &ioStatus, \ 00107 FSCTL_GET_RETRIEVAL_POINTERS, \ 00108 &startVcn, sizeof(ULONGLONG), \ 00109 fileMappings, FILEMAPSIZE * sizeof(ULONGLONG)); 00110 counter ++; 00111 if(NT_SUCCESS(Status)/* == STATUS_PENDING*/){ 00112 NtWaitForSingleObject(hFile,FALSE,NULL); 00113 Status = ioStatus.Status; 00114 } 00115 if(Status != STATUS_SUCCESS && Status != STATUS_BUFFER_OVERFLOW){ 00116 /* it always returns STATUS_END_OF_FILE for small files placed in MFT */ 00117 if(Status != STATUS_END_OF_FILE) 00118 DebugPrint("Dump failed for %ws: %x\n",pfn->name.Buffer,(UINT)Status); 00119 goto dump_fail; 00120 } 00121 00122 /* user must have a chance to break infinite loops */ 00123 if(CheckForStopEvent()){ 00124 if(counter > MAX_COUNTER) 00125 DebugPrint("Infinite main loop? %ws\n",pfn->name.Buffer); 00126 goto dump_fail; 00127 } 00128 00129 if(!fileMappings->NumberOfPairs && Status != STATUS_SUCCESS){ 00130 DebugPrint("Empty map of file %ws\n",pfn->name.Buffer); 00131 goto dump_fail; 00132 } 00133 00134 /* Loop through the buffer of number/cluster pairs. */ 00135 startVcn = fileMappings->StartVcn; 00136 for(i = 0; i < (ULONGLONG) fileMappings->NumberOfPairs; i++){ 00137 /* Infinite loop here will cause BSOD (in kernel mode driver only, of course). */ 00138 00139 /* 00140 * A compressed virtual run (0-filled) is 00141 * identified with a cluster offset of -1. 00142 */ 00143 if(fileMappings->Pair[i].Lcn == LLINVALID) goto next_run; 00144 00145 /* The following code may cause an infinite main loop (bug #2053941?), */ 00146 /* but for some 3.99 Gb files on FAT32 it works fine. */ 00147 if(fileMappings->Pair[i].Vcn == 0){ 00148 DebugPrint("Wrong map of file %ws\n",pfn->name.Buffer); 00149 goto next_run; 00150 } 00151 00152 block = (PBLOCKMAP)winx_list_insert_item((list_entry **)&pfn->blockmap,(list_entry *)block,sizeof(BLOCKMAP)); 00153 if(!block) goto dump_fail; 00154 block->lcn = fileMappings->Pair[i].Lcn; 00155 block->length = fileMappings->Pair[i].Vcn - startVcn; 00156 block->vcn = startVcn; 00157 00158 if(!wcscmp(pfn->name.Buffer,L"\\??\\L:\\go.zip")){ 00159 DebugPrint("VCN %I64u : LEN %I64u : LCN %I64u\n",block->vcn,block->length,block->lcn); 00160 } 00161 00162 pfn->clusters_total += block->length; 00163 pfn->n_fragments ++; 00164 /* 00165 * Sometimes normal file has more than one fragment, 00166 * but is not fragmented yet! 8-) 00167 */ 00168 if(block != pfn->blockmap && \ 00169 block->lcn != (block->prev_ptr->lcn + block->prev_ptr->length)) 00170 pfn->is_fragm = TRUE; 00171 next_run: 00172 startVcn = fileMappings->Pair[i].Vcn; 00173 } 00174 } while(Status != STATUS_SUCCESS); 00175 00176 /* Skip small directories placed in MFT (tested on 32-bit XP system). */ 00177 if(pfn->blockmap){ 00178 NtClose(hFile); 00179 winx_heap_free(FileMap); 00180 return TRUE; /* success */ 00181 } 00182 00183 dump_fail: 00184 DeleteBlockmap(pfn); 00185 pfn->clusters_total = pfn->n_fragments = 0; 00186 pfn->is_fragm = FALSE; 00187 NtClose(hFile); 00188 winx_heap_free(FileMap); 00189 return FALSE; 00190 } 00191