转载:https://www.iteye.com/blog/univasity-805234 https://blog.51cto.com/velika/1440105
源码:https://files.cnblogs.com/files/Toya/USN.7z
本程序需要管理员权限
1 #include2 #include 3 #include<string> 4 #include 5 #include 6 7 using namespace std; 8 9 bool isNTFS(string path); 10 HANDLE getHandle(string volName); 11 bool createUSN(HANDLE hVol, CREATE_USN_JOURNAL_DATA& cujd); 12 bool getUSNInfo(HANDLE hVol, USN_JOURNAL_DATA& ujd); 13 bool getUSNJournal(HANDLE hVol, USN_JOURNAL_DATA& ujd); 14 bool deleteUSN(HANDLE hVol, USN_JOURNAL_DATA& ujd); 15 16 int main(){ 17 //isNTFS("C:/"); 18 CREATE_USN_JOURNAL_DATA* cujd = new CREATE_USN_JOURNAL_DATA; 19 USN_JOURNAL_DATA* ujd = new USN_JOURNAL_DATA; 20 HANDLE hVol = getHandle("C:"); 21 createUSN(hVol, *cujd); 22 getUSNInfo(hVol, *ujd); 23 getUSNJournal(hVol, *ujd); 24 deleteUSN(hVol, *ujd); 25 system("pause"); 26 return 0; 27 } 28 29 //判断是否是NTFS盘 30 bool isNTFS(string path){//"C:/" 31 char sysNameBuf[MAX_PATH]; 32 int status = GetVolumeInformationA(path.c_str(), 33 NULL, 34 0, 35 NULL, 36 NULL, 37 NULL, 38 sysNameBuf, 39 MAX_PATH); 40 41 if (0 != status){ 42 if (0 == strcmp(sysNameBuf, "NTFS")){ 43 //printf(" 文件系统名 : %s\n", sysNameBuf); 44 cout << "盘符:" << path << "\n文件系统名:" << sysNameBuf << endl; 45 return true; 46 } 47 else { 48 printf(" 该驱动盘非 NTFS 格式 \n"); 49 return false; 50 } 51 52 } 53 return false; 54 } 55 56 /** 57 * step 02. 获取驱动盘句柄 58 */ 59 HANDLE getHandle(string volName){ 60 61 char fileName[MAX_PATH]; 62 fileName[0] = '\0'; 63 64 // 传入的文件名必须为\\.\C:的形式 65 strcpy_s(fileName, "\\\\.\\"); 66 strcat_s(fileName, volName.c_str()); 67 // 为了方便操作,这里转为string进行去尾 68 string fileNameStr = (string)fileName; 69 fileNameStr.erase(fileNameStr.find_last_of(":") + 1); 70 71 printf("驱动盘地址: %s\n", fileNameStr.data()); 72 73 // 调用该函数需要管理员权限 74 HANDLE hVol = CreateFileA(fileNameStr.data(), 75 GENERIC_READ | GENERIC_WRITE, // 可以为0 76 FILE_SHARE_READ | FILE_SHARE_WRITE, // 必须包含有FILE_SHARE_WRITE 77 NULL, // 这里不需要 78 OPEN_EXISTING, // 必须包含OPEN_EXISTING, CREATE_ALWAYS可能会导致错误 79 FILE_ATTRIBUTE_READONLY, // FILE_ATTRIBUTE_NORMAL可能会导致错误 80 NULL); // 这里不需要 81 82 if (INVALID_HANDLE_VALUE != hVol){ 83 //getHandleSuccess = true; 84 cout << "获取驱动盘句柄成功!\n"; 85 return hVol; 86 } 87 else{ 88 printf("获取驱动盘句柄失败 —— handle:%x error:%d\n", hVol, GetLastError()); 89 return 0; 90 } 91 return 0; 92 } 93 94 /** 95 * step 03. 初始化USN日志文件 96 */ 97 bool createUSN(HANDLE hVol, CREATE_USN_JOURNAL_DATA& cujd){ 98 DWORD br; 99 cujd.MaximumSize = 0; // 0表示使用默认值 100 cujd.AllocationDelta = 0; // 0表示使用默认值 101 bool status = DeviceIoControl(hVol, 102 FSCTL_CREATE_USN_JOURNAL, 103 &cujd, 104 sizeof(cujd), 105 NULL, 106 0, 107 &br, 108 NULL); 109 110 if (0 != status){ 111 //initUsnJournalSuccess = true; 112 return true; 113 } 114 else{ 115 printf("初始化USN日志文件失败 —— status:%x error:%d\n", status, GetLastError()); 116 return false; 117 } 118 return false; 119 } 120 121 /** 122 123 * step 04. 获取USN日志基本信息(用于后续操作) 124 125 * msdn:http://msdn.microsoft.com/en-us/library/aa364583%28v=VS.85%29.aspx 126 127 */ 128 bool getUSNInfo(HANDLE hVol, USN_JOURNAL_DATA& ujd){ 129 bool getBasicInfoSuccess = false; 130 DWORD br; 131 bool status = DeviceIoControl(hVol, 132 FSCTL_QUERY_USN_JOURNAL, 133 NULL, 134 0, 135 &ujd, 136 sizeof(ujd), 137 &br, 138 NULL); 139 if (0 != status){ 140 //getBasicInfoSuccess = true; 141 printf("获取USN日志基本信息成功\n"); 142 return true; 143 } 144 else{ 145 printf("获取USN日志基本信息失败 —— status:%x error:%d\n", status, GetLastError()); 146 return false; 147 } 148 return false; 149 } 150 151 bool getUSNJournal(HANDLE hVol, USN_JOURNAL_DATA& ujd){ 152 MFT_ENUM_DATA_V0 med; 153 med.StartFileReferenceNumber = 0; 154 med.LowUsn = ujd.FirstUsn; 155 med.HighUsn = ujd.NextUsn; 156 #define BUF_LEN 4096 157 CHAR buffer[BUF_LEN]; // 用于储存记录的缓冲 , 尽量足够地大 158 DWORD usnDataSize = 0; 159 PUSN_RECORD UsnRecord; 160 while (0 != DeviceIoControl(hVol, 161 FSCTL_ENUM_USN_DATA, 162 &med, 163 sizeof (med), 164 buffer, 165 BUF_LEN, 166 &usnDataSize, 167 NULL)) 168 { 169 DWORD dwRetBytes = usnDataSize - sizeof (USN); 170 // 找到第一个 USN 记录 171 // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx ): 172 // return a USN followed by zero or more change journal records, each in a USN_RECORD structure. 173 UsnRecord = (PUSN_RECORD)(((PCHAR)buffer) + sizeof (USN)); 174 printf(" ********************************** \n"); 175 while (dwRetBytes>0){ 176 // 打印获取到的信息 177 const int strLen = UsnRecord->FileNameLength; 178 char fileName[MAX_PATH] = { 0 }; 179 WideCharToMultiByte(CP_OEMCP, NULL, UsnRecord->FileName, strLen / 2, fileName, strLen, NULL, FALSE); 180 printf("FileName: %s\n", fileName); 181 // 下面两个 file reference number 可以用来获取文件的路径信息 182 printf("FileReferenceNumber: %xI64\n", UsnRecord->FileReferenceNumber); 183 printf("ParentFileReferenceNumber: %xI64\n", UsnRecord->ParentFileReferenceNumber); 184 printf("\n"); 185 // 获取下一个记录 186 DWORD recordLen = UsnRecord->RecordLength; 187 dwRetBytes -= recordLen; 188 UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) + recordLen); 189 } 190 // 获取下一页数据, MTF 大概是分多页来储存的吧? 191 // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx ): 192 // The USN returned as the first item in the output buffer is the USN of the next record number to be retrieved. 193 // Use this value to continue reading records from the end boundary forward. 194 med.StartFileReferenceNumber = *(USN *)&buffer; 195 } 196 return true; 197 } 198 199 /** 200 * step 06. 删除 USN 日志文件 ( 当然也可以不删除 ) 201 */ 202 bool deleteUSN(HANDLE hVol, USN_JOURNAL_DATA& ujd){ 203 DELETE_USN_JOURNAL_DATA dujd; 204 dujd.UsnJournalID = ujd.UsnJournalID; 205 dujd.DeleteFlags = USN_DELETE_FLAG_DELETE; 206 DWORD br; 207 int status = DeviceIoControl(hVol, 208 FSCTL_DELETE_USN_JOURNAL, 209 &dujd, 210 sizeof (dujd), 211 NULL, 212 0, 213 &br, 214 NULL); 215 if (0 != status){ 216 CloseHandle(hVol); 217 printf(" 成功删除 USN 日志文件 !\n"); 218 return true; 219 } 220 else { 221 CloseHandle(hVol); 222 printf(" 删除 USN 日志文件失败 —— status:%x error:%d\n", status, GetLastError()); 223 return false; 224 } 225 return false; 226 }
运行结果: