Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
14 KiB

  1. #include "ulib.hxx"
  2. #include "drive.hxx"
  3. #include "ifssys.hxx"
  4. #include "ntfssa.hxx"
  5. #include "frs.hxx"
  6. #include "attrib.hxx"
  7. #include "mftfile.hxx"
  8. #include "bitfrs.hxx"
  9. #include "ntfsbit.hxx"
  10. #include "upfile.hxx"
  11. #include "upcase.hxx"
  12. #include "rfatsa.hxx"
  13. #include "rcache.hxx"
  14. #include "hmem.hxx"
  15. #include "recordpg.hxx"
  16. #include "crack.hxx"
  17. #include "diskedit.h"
  18. extern "C" {
  19. #include <stdio.h>
  20. }
  21. extern PLOG_IO_DP_DRIVE Drive;
  22. TCHAR Path[MAX_PATH];
  23. VOID
  24. CrackNtfsPath(
  25. IN HWND WindowHandle
  26. )
  27. {
  28. DSTRING path;
  29. NTFS_SA ntfssa;
  30. MESSAGE msg;
  31. NTFS_MFT_FILE mft;
  32. NTFS_BITMAP_FILE bitmap_file;
  33. NTFS_ATTRIBUTE bitmap_attribute;
  34. NTFS_BITMAP volume_bitmap;
  35. NTFS_UPCASE_FILE upcase_file;
  36. NTFS_ATTRIBUTE upcase_attribute;
  37. NTFS_UPCASE_TABLE upcase_table;
  38. NTFS_FILE_RECORD_SEGMENT file_record;
  39. BOOLEAN error;
  40. BOOLEAN system_file;
  41. ULONG file_number;
  42. TCHAR buf[100];
  43. if (!path.Initialize(Path)) {
  44. wsprintf(buf, TEXT("Out of memory"));
  45. MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONEXCLAMATION);
  46. return;
  47. }
  48. if (!Drive ||
  49. !ntfssa.Initialize(Drive, &msg) ||
  50. !ntfssa.Read() ||
  51. !mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
  52. ntfssa.QueryClusterFactor(),
  53. ntfssa.QueryFrsSize(),
  54. ntfssa.QueryVolumeSectors(), NULL, NULL) ||
  55. !mft.Read() ||
  56. !bitmap_file.Initialize(mft.GetMasterFileTable()) ||
  57. !bitmap_file.Read() ||
  58. !bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
  59. !volume_bitmap.Initialize(ntfssa.QueryVolumeSectors() /
  60. (ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
  61. !volume_bitmap.Read(&bitmap_attribute) ||
  62. !upcase_file.Initialize(mft.GetMasterFileTable()) ||
  63. !upcase_file.Read() ||
  64. !upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
  65. !upcase_table.Initialize(&upcase_attribute) ||
  66. !mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
  67. ntfssa.QueryClusterFactor(),
  68. ntfssa.QueryFrsSize(),
  69. ntfssa.QueryVolumeSectors(),
  70. &volume_bitmap,
  71. &upcase_table) ||
  72. !mft.Read()) {
  73. swprintf(buf, TEXT("Could not init NTFS data structures"));
  74. MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONEXCLAMATION);
  75. return;
  76. }
  77. if (!ntfssa.QueryFrsFromPath(&path, mft.GetMasterFileTable(),
  78. &volume_bitmap, &file_record, &system_file, &error)) {
  79. wsprintf(buf, TEXT("File not found."));
  80. MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONINFORMATION);
  81. return;
  82. }
  83. file_number = file_record.QueryFileNumber().GetLowPart();
  84. wsprintf(buf, TEXT("The given path points to file record 0x%X"), file_number);
  85. MessageBox(WindowHandle, buf, TEXT("Path Image"), MB_OK);
  86. }
  87. BOOLEAN
  88. BacktrackFrs(
  89. IN VCN FileNumber,
  90. IN OUT PNTFS_MASTER_FILE_TABLE Mft,
  91. OUT PWCHAR PathBuffer,
  92. IN ULONG BufferLength,
  93. OUT PULONG PathLength
  94. )
  95. /*++
  96. Routine Description:
  97. This function finds a path from the root to a given FRS.
  98. Arguments:
  99. FileNumber -- Supplies the file number of the target FRS.
  100. Mft -- Supplies the volume's Master File Table.
  101. PathBuffer -- Receives a path to the FRS.
  102. BufferLength -- Supplies the length (in characters) of
  103. the client's buffer.
  104. PathLength -- Receives the length (in characters) of
  105. the path.
  106. Return Value:
  107. TRUE upon successful completion. The returned path may
  108. not be NULL-terminated.
  109. --*/
  110. {
  111. NTFS_FILE_RECORD_SEGMENT CurrentFrs;
  112. NTFS_ATTRIBUTE FileNameAttribute;
  113. VCN ParentFileNumber;
  114. PCFILE_NAME FileName;
  115. ULONG i;
  116. BOOLEAN Error;
  117. if( FileNumber == ROOT_FILE_NAME_INDEX_NUMBER ) {
  118. // This is the root; return a NULL path.
  119. //
  120. *PathLength = 0;
  121. return TRUE;
  122. }
  123. // Initialize the FRS and extract a name (any name will do).
  124. //
  125. if( !CurrentFrs.Initialize( FileNumber, Mft ) ||
  126. !CurrentFrs.Read() ||
  127. !CurrentFrs.QueryAttribute( &FileNameAttribute, &Error, $FILE_NAME ) ||
  128. !FileNameAttribute.IsResident() ) {
  129. return FALSE;
  130. }
  131. FileName = (PCFILE_NAME)FileNameAttribute.GetResidentValue();
  132. ParentFileNumber.Set( FileName->ParentDirectory.LowPart,
  133. (LONG)FileName->ParentDirectory.HighPart );
  134. // Now recurse into this file's parent.
  135. //
  136. if( !BacktrackFrs( ParentFileNumber,
  137. Mft,
  138. PathBuffer,
  139. BufferLength,
  140. PathLength ) ) {
  141. return FALSE;
  142. }
  143. // Add this file's name to the path.
  144. //
  145. if( *PathLength + FileName->FileNameLength + 1 > BufferLength ) {
  146. // Buffer is too small.
  147. //
  148. return FALSE;
  149. }
  150. PathBuffer[*PathLength] = '\\';
  151. for( i = 0; i < FileName->FileNameLength; i++ ) {
  152. PathBuffer[*PathLength+1+i] = FileName->FileName[i];
  153. }
  154. *PathLength += 1 + FileName->FileNameLength;
  155. return TRUE;
  156. }
  157. BOOLEAN
  158. BacktrackFrsFromScratch(
  159. IN HWND WindowHandle,
  160. IN VCN FileNumber
  161. )
  162. /*++
  163. Routine Description:
  164. This function finds a path from the root to a given
  165. FRS; it sets up the MFT and its helper objects as
  166. needed.
  167. Arguments:
  168. WindowHandle -- Supplies a handle to the parent window.
  169. FileNumber -- Supplies the file number of the target FRS.
  170. Return Value:
  171. TRUE upon successful completion. The returned path may
  172. not be NULL-terminated.
  173. --*/
  174. {
  175. WCHAR WPath[MAX_PATH];
  176. NTFS_SA ntfssa;
  177. MESSAGE msg;
  178. NTFS_MFT_FILE mft;
  179. NTFS_BITMAP_FILE bitmap_file;
  180. NTFS_ATTRIBUTE bitmap_attribute;
  181. NTFS_BITMAP volume_bitmap;
  182. NTFS_UPCASE_FILE upcase_file;
  183. NTFS_ATTRIBUTE upcase_attribute;
  184. NTFS_UPCASE_TABLE upcase_table;
  185. BOOLEAN error;
  186. ULONG BufferLength, PathLength, i;
  187. BufferLength = sizeof(WPath);
  188. if (!Drive ||
  189. !ntfssa.Initialize(Drive, &msg) ||
  190. !ntfssa.Read() ||
  191. !mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
  192. ntfssa.QueryClusterFactor(),
  193. ntfssa.QueryFrsSize(),
  194. ntfssa.QueryVolumeSectors(), NULL, NULL) ||
  195. !mft.Read() ||
  196. !bitmap_file.Initialize(mft.GetMasterFileTable()) ||
  197. !bitmap_file.Read() ||
  198. !bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
  199. !volume_bitmap.Initialize(Drive->QuerySectors()/
  200. (ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
  201. !volume_bitmap.Read(&bitmap_attribute) ||
  202. !upcase_file.Initialize(mft.GetMasterFileTable()) ||
  203. !upcase_file.Read() ||
  204. !upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
  205. !upcase_table.Initialize(&upcase_attribute) ||
  206. !mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
  207. ntfssa.QueryClusterFactor(),
  208. ntfssa.QueryFrsSize(),
  209. ntfssa.QueryVolumeSectors(),
  210. &volume_bitmap,
  211. &upcase_table) ||
  212. !mft.Read() ||
  213. !bitmap_file.Initialize(mft.GetMasterFileTable()) ||
  214. !bitmap_file.Read() ||
  215. !bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
  216. !volume_bitmap.Initialize(Drive->QuerySectors()/
  217. (ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
  218. !volume_bitmap.Read(&bitmap_attribute) ||
  219. !upcase_file.Initialize(mft.GetMasterFileTable()) ||
  220. !upcase_file.Read() ||
  221. !upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
  222. !upcase_table.Initialize(&upcase_attribute) ||
  223. !BacktrackFrs( FileNumber, mft.GetMasterFileTable(), WPath,
  224. BufferLength, &PathLength ) ) {
  225. return FALSE;
  226. }
  227. MessageBox(WindowHandle, WPath, TEXT("Path Image"), MB_OK);
  228. return TRUE;
  229. }
  230. VOID
  231. CrackFatPath(
  232. IN HWND WindowHandle
  233. )
  234. {
  235. DSTRING path;
  236. REAL_FAT_SA fatsa;
  237. MESSAGE msg;
  238. ULONG cluster_number;
  239. TCHAR buf[100];
  240. if (!path.Initialize(Path) ||
  241. !Drive ||
  242. !fatsa.Initialize(Drive, &msg) ||
  243. !fatsa.FAT_SA::Read()) {
  244. return;
  245. }
  246. cluster_number = fatsa.QueryFileStartingCluster(&path);
  247. wsprintf(buf, TEXT("The given path points to cluster 0x%X"), cluster_number);
  248. MessageBox(WindowHandle, buf, TEXT("Path Image"), MB_OK);
  249. }
  250. VOID
  251. CrackLsn(
  252. IN HWND WindowHandle
  253. )
  254. {
  255. extern LSN Lsn;
  256. TCHAR buf[100];
  257. LONGLONG FileOffset;
  258. (void)GetLogPageSize(Drive);
  259. LfsTruncateLsnToLogPage(Drive, Lsn, &FileOffset);
  260. wsprintf(buf, TEXT("page at %x, offset %x, seq %x"), (ULONG)FileOffset,
  261. LfsLsnToPageOffset(Drive, Lsn) , LfsLsnToSeqNumber(Drive, Lsn));
  262. MessageBox(WindowHandle, buf, TEXT("LSN"), MB_OK);
  263. }
  264. //
  265. // CrackNextLsn -- given an LSN in the Lsn variable, find the
  266. // LSN following that one in the log file. This involves
  267. // reading the log record for the given lsn to find it's
  268. // size, and figuring the page and offset of the following
  269. // lsn from that.
  270. //
  271. BOOLEAN
  272. CrackNextLsn(
  273. IN HWND WindowHandle
  274. )
  275. {
  276. extern LSN Lsn;
  277. TCHAR buf[100];
  278. NTFS_SA ntfssa;
  279. NTFS_MFT_FILE mft;
  280. ULONG PageOffset;
  281. LONGLONG FileOffset;
  282. MESSAGE msg;
  283. BOOLEAN error;
  284. NTFS_FILE_RECORD_SEGMENT frs;
  285. NTFS_ATTRIBUTE attrib;
  286. LFS_RECORD_HEADER RecordHeader;
  287. ULONG bytes_read;
  288. ULONG RecordLength;
  289. ULONG PageSize;
  290. ULONGLONG NextLsn;
  291. ULONG SeqNumber;
  292. if (0 == (PageSize = GetLogPageSize(Drive))) {
  293. return FALSE;
  294. }
  295. if (!Drive)
  296. return FALSE;
  297. if (!ntfssa.Initialize(Drive, &msg))
  298. return FALSE;
  299. if (!ntfssa.Read())
  300. return FALSE;
  301. if (!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
  302. ntfssa.QueryClusterFactor(), ntfssa.QueryFrsSize(),
  303. ntfssa.QueryVolumeSectors(), NULL, NULL))
  304. return FALSE;
  305. if (!mft.Read())
  306. return FALSE;
  307. if (!frs.Initialize((VCN)LOG_FILE_NUMBER, &mft))
  308. return FALSE;
  309. if (!frs.Read())
  310. return FALSE;
  311. if (!frs.QueryAttribute(&attrib, &error, $DATA, NULL)) {
  312. return FALSE;
  313. }
  314. LfsTruncateLsnToLogPage(Drive, Lsn, &FileOffset);
  315. PageOffset = LfsLsnToPageOffset(Drive, Lsn);
  316. SeqNumber = (ULONG)LfsLsnToSeqNumber(Drive, Lsn);
  317. if (!attrib.Read((PVOID)&RecordHeader, ULONG(PageOffset | FileOffset),
  318. LFS_RECORD_HEADER_SIZE, &bytes_read))
  319. return FALSE;
  320. if (bytes_read != LFS_RECORD_HEADER_SIZE) {
  321. return FALSE;
  322. }
  323. RecordLength = LFS_RECORD_HEADER_SIZE + RecordHeader.ClientDataLength;
  324. if (PageOffset + RecordLength < PageSize &&
  325. PageSize - (PageOffset + RecordLength) >= LFS_RECORD_HEADER_SIZE) {
  326. //
  327. // the current record ends on this page, and the next record begins
  328. // immediately after
  329. //
  330. PageOffset += RecordLength;
  331. } else if (PageSize - (PageOffset+RecordLength) < LFS_RECORD_HEADER_SIZE) {
  332. //
  333. // The next record header will not fit on this page... it
  334. // will begin on the next page immediately following the page
  335. // header
  336. //
  337. FileOffset += PageSize;
  338. PageOffset = LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
  339. } else {
  340. //
  341. // the next log record starts on a following page
  342. //
  343. ULONG left;
  344. ULONG page_capacity;
  345. left = PageSize - (PageOffset + RecordLength);
  346. page_capacity = PageSize - LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
  347. PageOffset += (left / page_capacity + 1) * PageSize;
  348. FileOffset = left % page_capacity + LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
  349. }
  350. // create lsn from FileOffset + PageOffset
  351. NextLsn = LfsFileOffsetToLsn(Drive, FileOffset | PageOffset, SeqNumber);
  352. wsprintf(buf, TEXT("Next LSN %x:%x, at %x + %x"), ((PLSN)&NextLsn)->HighPart,
  353. ((PLSN)&NextLsn)->LowPart, (ULONG)FileOffset, (ULONG)PageOffset);
  354. MessageBox(WindowHandle, buf, TEXT("LSN"), MB_OK);
  355. return TRUE;
  356. }
  357. struct {
  358. ULONG Code;
  359. PTCHAR Name;
  360. } TypeCodeNameTab[] = {
  361. { $UNUSED, TEXT("$UNUSED") },
  362. { $STANDARD_INFORMATION, TEXT("$STANDARD_INFORMATION") },
  363. { $ATTRIBUTE_LIST, TEXT("$ATTRIBUTE_LIST") },
  364. { $FILE_NAME, TEXT("$FILE_NAME") },
  365. { $OBJECT_ID, TEXT("$OBJECT_ID") },
  366. { $SECURITY_DESCRIPTOR, TEXT("$SECURITY_DESCRIPTOR") },
  367. { $VOLUME_NAME, TEXT("$VOLUME_NAME") },
  368. { $VOLUME_INFORMATION, TEXT("$VOLUME_INFORMATION") },
  369. { $DATA, TEXT("$DATA") },
  370. { $INDEX_ROOT, TEXT("$INDEX_ROOT") },
  371. { $INDEX_ALLOCATION, TEXT("$INDEX_ALLOCATION") },
  372. { $BITMAP, TEXT("$BITMAP") },
  373. { $SYMBOLIC_LINK, TEXT("$SYMBOLIC_LINK") },
  374. { $EA_INFORMATION, TEXT("$EA_INFORMATION") },
  375. { $EA_DATA, TEXT("$EA_DATA") },
  376. { $END, TEXT("$END") }
  377. };
  378. PTCHAR
  379. GetNtfsAttributeTypeCodeName(
  380. IN ULONG Code
  381. )
  382. {
  383. for (INT i = 0; $END != TypeCodeNameTab[i].Code; ++i) {
  384. if (Code == TypeCodeNameTab[i].Code) {
  385. return TypeCodeNameTab[i].Name;
  386. }
  387. }
  388. return NULL;
  389. }