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.

1267 lines
30 KiB

  1. #include "imagpart.h"
  2. #include <malloc.h>
  3. #include <stddef.h>
  4. #include "ntfs.h"
  5. //
  6. // NTFS boot sector.
  7. //
  8. #pragma pack(1)
  9. typedef struct _NTFS_BOOT_SECTOR {
  10. BYTE Jump[3];
  11. BYTE Oem[8];
  12. USHORT BytesPerSector;
  13. BYTE SectorsPerCluster;
  14. USHORT ReservedSectors;
  15. BYTE Fats;
  16. USHORT RootEntries;
  17. USHORT Sectors;
  18. BYTE Media;
  19. USHORT SectorsPerFat;
  20. USHORT SectorsPerTrack;
  21. USHORT Heads;
  22. ULONG HiddenSectors;
  23. ULONG LargeSectors;
  24. BYTE Unused0[4];
  25. ULONG NumberSectors;
  26. ULONG NumberSectorsh;
  27. ULONG MftStartLcn;
  28. ULONG MftStartLcnh;
  29. ULONG Mft2StartLcn;
  30. ULONG Mft2StartLcnh;
  31. CHAR ClustersPerFileRecordSegment;
  32. BYTE Unused1[3];
  33. CHAR DefClusPerIndexAllocBuffer;
  34. BYTE Unused2[3];
  35. ULONG SerialNumberl;
  36. ULONG SerialNumberh;
  37. ULONG Checksum;
  38. BYTE BootStrap[512-86];
  39. USHORT AA55Signature;
  40. } NTFS_BOOT_SECTOR, _far *FPNTFS_BOOT_SECTOR;
  41. #pragma pack()
  42. //
  43. // Globals, which make our life easier.
  44. //
  45. BYTE SectorsPerFrs;
  46. unsigned SegmentsInMft;
  47. FPFILE_RECORD_SEGMENT FrsScratchBuffer;
  48. FPFILE_RECORD_SEGMENT MftLcnFrsScratchBuffer;
  49. typedef struct _MFT_MAPPING {
  50. ULONG Start;
  51. BYTE Count;
  52. } MFT_MAPPING, *PMFT_MAPPING, _far *FPMFT_MAPPING;
  53. FPMFT_MAPPING MftMappings;
  54. FPATTRIBUTE_LIST_ENTRY AttrListBuffer;
  55. #define ATTR_LIST_BUFFER_SIZE 8192
  56. BOOL
  57. pNtfsSetUpMft(
  58. IN HPARTITION PartitionHandle,
  59. IN PARTITION_IMAGE *PartitionImage,
  60. IN FPNTFS_BOOT_SECTOR BootSector
  61. );
  62. BOOL
  63. pNtfsTransferVolumeBitmap(
  64. IN HPARTITION PartitionHandle,
  65. IN PARTITION_IMAGE *PartitionImage,
  66. IN UINT OutputFileHandle
  67. );
  68. BOOL
  69. pNtfsProcessVolumeBitmap(
  70. IN OUT PARTITION_IMAGE *PartitionImage,
  71. IN UINT FileHandle
  72. );
  73. BOOL
  74. pNtfsMultiSectorFixup(
  75. IN OUT FPVOID Buffer
  76. );
  77. FPATTRIBUTE_RECORD
  78. pNtfsLocateAttributeRecord(
  79. IN FPFILE_RECORD_SEGMENT MftFrsBuffer,
  80. IN ULONG TypeCode
  81. );
  82. BOOL
  83. pNtfsReadWholeAttribute(
  84. IN HPARTITION PartitionHandle,
  85. IN PARTITION_IMAGE *PartitionImage,
  86. IN FPATTRIBUTE_RECORD Attribute,
  87. OUT FPVOID Buffer, OPTIONAL
  88. IN UINT OutputFileHandle OPTIONAL
  89. );
  90. BOOL
  91. pNtfsComputeMftLcn(
  92. IN HPARTITION PartitionHandle,
  93. IN ULONG Vcn,
  94. OUT ULONG *Lcn
  95. );
  96. BOOL
  97. pNtfsComputeLcn(
  98. IN ULONG Vcn,
  99. IN FPATTRIBUTE_RECORD Attribute,
  100. OUT ULONG *Lcn,
  101. OUT UINT *RunLength
  102. );
  103. ULONG
  104. pNtfsLcnFromMappingPair(
  105. IN FPBYTE p
  106. );
  107. ULONG
  108. pNtfsVcnFromMappingPair(
  109. IN FPBYTE p
  110. );
  111. BOOL
  112. pNtfsReadFrs(
  113. IN HPARTITION PartitionHandle,
  114. IN PARTITION_IMAGE *PartitionImage,
  115. IN ULONG FileNumber,
  116. OUT FPVOID Buffer
  117. );
  118. BOOL
  119. pNtfsReadMftSectors(
  120. IN HPARTITION PartitionHandle,
  121. IN PARTITION_IMAGE *PartitionImage,
  122. IN ULONG Vbn,
  123. OUT FPBYTE Buffer
  124. );
  125. BOOL
  126. pNtfsSearchFrsForAttrList(
  127. IN HPARTITION PartitionHandle,
  128. IN PARTITION_IMAGE *PartitionImage,
  129. IN FPFILE_RECORD_SEGMENT FrsBuffer,
  130. IN ULONG TypeCode,
  131. OUT ULONG *Frn
  132. );
  133. BOOL
  134. NtfsIsNtfs(
  135. IN HPARTITION PartitionHandle
  136. )
  137. {
  138. FPNTFS_BOOT_SECTOR BootSector;
  139. if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
  140. return(FALSE);
  141. }
  142. BootSector = IoBuffer;
  143. //
  144. // Ensure that NTFS appears in the OEM field.
  145. //
  146. if(strncmp(BootSector->Oem,"NTFS ",8)) {
  147. return(FALSE);
  148. }
  149. //
  150. // Check bytes per sector
  151. //
  152. if(BootSector->BytesPerSector != 512) {
  153. return(FALSE);
  154. }
  155. //
  156. // Other checks.
  157. //
  158. if((BootSector->SectorsPerCluster != 1)
  159. && (BootSector->SectorsPerCluster != 2)
  160. && (BootSector->SectorsPerCluster != 4)
  161. && (BootSector->SectorsPerCluster != 8)
  162. && (BootSector->SectorsPerCluster != 16)
  163. && (BootSector->SectorsPerCluster != 32)
  164. && (BootSector->SectorsPerCluster != 64)
  165. && (BootSector->SectorsPerCluster != 128)) {
  166. return(FALSE);
  167. }
  168. if(BootSector->ReservedSectors
  169. || BootSector->Fats
  170. || BootSector->RootEntries
  171. || BootSector->Sectors
  172. || BootSector->SectorsPerFat
  173. || BootSector->LargeSectors) {
  174. return(FALSE);
  175. }
  176. //
  177. // ClustersPerFileRecord can be less than zero if file records
  178. // are smaller than clusters. This number is the negative of a shift count.
  179. // If clusters are smaller than file records then this number is
  180. // still the clusters per file records.
  181. //
  182. if(BootSector->ClustersPerFileRecordSegment <= -9) {
  183. if(BootSector->ClustersPerFileRecordSegment < -31) {
  184. return(FALSE);
  185. }
  186. } else if((BootSector->ClustersPerFileRecordSegment != 1)
  187. && (BootSector->ClustersPerFileRecordSegment != 2)
  188. && (BootSector->ClustersPerFileRecordSegment != 4)
  189. && (BootSector->ClustersPerFileRecordSegment != 8)
  190. && (BootSector->ClustersPerFileRecordSegment != 16)
  191. && (BootSector->ClustersPerFileRecordSegment != 32)
  192. && (BootSector->ClustersPerFileRecordSegment != 64)) {
  193. return(FALSE);
  194. }
  195. //
  196. // ClustersPerIndexAllocationBuffer can be less than zero if index buffers
  197. // are smaller than clusters. This number is the negative of a shift count.
  198. // If clusters are smaller than index buffers then this number is
  199. // still the clusters per index buffers.
  200. //
  201. if(BootSector->DefClusPerIndexAllocBuffer <= -9) {
  202. if(BootSector->DefClusPerIndexAllocBuffer < -31) {
  203. return(FALSE);
  204. }
  205. } else if((BootSector->DefClusPerIndexAllocBuffer != 1)
  206. && (BootSector->DefClusPerIndexAllocBuffer != 2)
  207. && (BootSector->DefClusPerIndexAllocBuffer != 4)
  208. && (BootSector->DefClusPerIndexAllocBuffer != 8)
  209. && (BootSector->DefClusPerIndexAllocBuffer != 16)
  210. && (BootSector->DefClusPerIndexAllocBuffer != 32)
  211. && (BootSector->DefClusPerIndexAllocBuffer != 64)) {
  212. return(FALSE);
  213. }
  214. return(TRUE);
  215. }
  216. BOOL
  217. NtfsInitializeVolumeData(
  218. IN HPARTITION PartitionHandle,
  219. OUT ULONG *TotalSectorCount,
  220. OUT ULONG *NonClusterSectors,
  221. OUT ULONG *ClusterCount,
  222. OUT BYTE *SectorsPerCluster
  223. )
  224. {
  225. FPNTFS_BOOT_SECTOR BootSector;
  226. if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
  227. fprintf(stderr,"\n");
  228. fprintf(stderr,textReadFailedAtSector,0L);
  229. fprintf(stderr,"\n");
  230. return(FALSE);
  231. }
  232. BootSector = IoBuffer;
  233. //
  234. // The mirror boot sector is not included in the sector count
  235. // in the bpb.
  236. //
  237. *TotalSectorCount = BootSector->NumberSectors + 1;
  238. *ClusterCount = BootSector->NumberSectors / BootSector->SectorsPerCluster;
  239. *NonClusterSectors = 0;
  240. *SectorsPerCluster = BootSector->SectorsPerCluster;
  241. return(TRUE);
  242. }
  243. BOOL
  244. NtfsBuildClusterBitmap(
  245. IN HPARTITION PartitionHandle,
  246. IN UINT FileHandle,
  247. IN OUT PARTITION_IMAGE *PartitionImage
  248. )
  249. {
  250. FPNTFS_BOOT_SECTOR BootSector;
  251. ULONG u;
  252. //
  253. // Load the boot sector, as we need the bpb fields.
  254. //
  255. BootSector = (FPNTFS_BOOT_SECTOR)((FPBYTE)IoBuffer+(62*512));
  256. if(!ReadPartition(PartitionHandle,0,1,BootSector)) {
  257. fprintf(stderr,"\n");
  258. fprintf(stderr,textReadFailedAtSector,0L);
  259. fprintf(stderr,"\n");
  260. return(FALSE);
  261. }
  262. //
  263. // Validate that we think we can deal with this drive. We impose
  264. // some limitations because of 16 bitness, memory constraints, etc.
  265. //
  266. // We disallow:
  267. //
  268. // Volumes with more than 2^32 sectors
  269. // Volumes with a cluster size > 16K
  270. // Volumes with > 16K per FRS
  271. //
  272. if(BootSector->NumberSectorsh) {
  273. fprintf(stderr,"\n");
  274. fprintf(stderr,textNtfsUnsupportedConfig,0);
  275. fprintf(stderr,"\n");
  276. return(FALSE);
  277. }
  278. if(BootSector->SectorsPerCluster > 32) {
  279. fprintf(stderr,"\n");
  280. fprintf(stderr,textNtfsUnsupportedConfig,1);
  281. fprintf(stderr,"\n");
  282. return(FALSE);
  283. }
  284. if(BootSector->ClustersPerFileRecordSegment < 0) {
  285. u = (1L << (0 - BootSector->ClustersPerFileRecordSegment)) / 512;
  286. } else {
  287. u = BootSector->ClustersPerFileRecordSegment * BootSector->SectorsPerCluster;
  288. }
  289. if(u > 32) {
  290. fprintf(stderr,"\n");
  291. fprintf(stderr,textNtfsUnsupportedConfig,2);
  292. fprintf(stderr,"\n");
  293. return(FALSE);
  294. }
  295. SectorsPerFrs = (BYTE)u;
  296. //
  297. // Initialize mapping information for the MFT
  298. //
  299. if(!pNtfsSetUpMft(PartitionHandle,PartitionImage,BootSector)) {
  300. return(FALSE);
  301. }
  302. //
  303. // Transfer the volume bitmap to the output file.
  304. //
  305. if(!pNtfsTransferVolumeBitmap(PartitionHandle,PartitionImage,FileHandle)) {
  306. return(FALSE);
  307. }
  308. //
  309. // Analyze and fix up the bitmap.
  310. //
  311. if(!pNtfsProcessVolumeBitmap(PartitionImage,FileHandle)) {
  312. return(FALSE);
  313. }
  314. return(TRUE);
  315. }
  316. BOOL
  317. pNtfsSetUpMft(
  318. IN HPARTITION PartitionHandle,
  319. IN PARTITION_IMAGE *PartitionImage,
  320. IN FPNTFS_BOOT_SECTOR BootSector
  321. )
  322. {
  323. ULONG Vbn,Vcn,Lcn,Lbn;
  324. BYTE SectorOffset;
  325. BYTE Remaining;
  326. BYTE Count;
  327. BYTE xCount;
  328. ULONG xStart;
  329. FPATTRIBUTE_RECORD Attribute;
  330. FPATTRIBUTE_LIST_ENTRY AttrListEntry;
  331. unsigned ArraySize;
  332. BOOL b;
  333. printf(textInitNtfsDataStruct);
  334. //
  335. // Allocate a scratch buffer to hold a buffered FRS
  336. //
  337. FrsScratchBuffer = malloc(SectorsPerFrs * 512);
  338. if(!FrsScratchBuffer) {
  339. fprintf(stderr,"\n%s\n",textOOM);
  340. return(FALSE);
  341. }
  342. //
  343. // Allocate a scratch buffer for lookups
  344. //
  345. MftLcnFrsScratchBuffer = malloc(SectorsPerFrs * 512);
  346. if(!MftLcnFrsScratchBuffer) {
  347. fprintf(stderr,"\n%s\n",textOOM);
  348. return(FALSE);
  349. }
  350. //
  351. // Allocate an initial buffer to store mappings.
  352. //
  353. MftMappings = malloc(sizeof(MFT_MAPPING));
  354. if(!MftMappings) {
  355. fprintf(stderr,"\n%s\n",textOOM);
  356. return(FALSE);
  357. }
  358. ArraySize = 1;
  359. //
  360. // Allocate an attribute list buffer.
  361. //
  362. AttrListBuffer = malloc(ATTR_LIST_BUFFER_SIZE);
  363. if(!AttrListBuffer) {
  364. fprintf(stderr,"\n%s\n",textOOM);
  365. return(FALSE);
  366. }
  367. //
  368. // Read FRS 0 into the first MFT FRS buffer, being sure
  369. // to resolve the Update Sequence Array. Remember the physical
  370. // location in the Lbn array.
  371. //
  372. MftMappings[0].Start = BootSector->MftStartLcn * BootSector->SectorsPerCluster;
  373. MftMappings[0].Count = SectorsPerFrs;
  374. SegmentsInMft = 1;
  375. if(!ReadPartition(PartitionHandle,MftMappings[0].Start,MftMappings[0].Count,(FPBYTE)IoBuffer+(61*512))) {
  376. fprintf(stderr,"\n");
  377. fprintf(stderr,textReadFailedAtSector,MftMappings[0].Start);
  378. fprintf(stderr,"\n");
  379. return(FALSE);
  380. }
  381. memmove(FrsScratchBuffer,(FPBYTE)IoBuffer+(61*512),MftMappings[0].Count*512);
  382. printf(".");
  383. if(!pNtfsMultiSectorFixup(FrsScratchBuffer)) {
  384. return(FALSE);
  385. }
  386. printf(".");
  387. //
  388. // Determine whether the MFT has an Attribute List attribute,
  389. // and if so, read it.
  390. //
  391. if(Attribute = pNtfsLocateAttributeRecord(FrsScratchBuffer,$ATTRIBUTE_LIST)) {
  392. b = pNtfsReadWholeAttribute(
  393. PartitionHandle,
  394. PartitionImage,
  395. Attribute,
  396. AttrListBuffer,
  397. 0
  398. );
  399. if(!b) {
  400. return(FALSE);
  401. }
  402. printf(".");
  403. AttrListEntry = AttrListBuffer;
  404. //
  405. // Traverse the attribute list looking for the first
  406. // entry for the $DATA type. We know it must have at least one.
  407. // Note that we then immediately skip this one because we already
  408. // handled the 0th FRS.
  409. //
  410. while(AttrListEntry->TypeCode != $DATA) {
  411. AttrListEntry = (FPATTRIBUTE_LIST_ENTRY)((FPBYTE)AttrListEntry + AttrListEntry->Length);
  412. }
  413. do {
  414. AttrListEntry = (FPATTRIBUTE_LIST_ENTRY)((FPBYTE)AttrListEntry + AttrListEntry->Length);
  415. if(AttrListEntry->TypeCode == $DATA) {
  416. //
  417. // Find the start sector and sector count for the runs for this
  418. // file record (max 2 runs). The mapping for this must be
  419. // in a file record already visited. Find the Vcn and cluster
  420. // offset for this FRS. Use LookupMftLcn to find the Lcn.
  421. //
  422. // Convert from Frs to sectors, then to Vcn.
  423. //
  424. Vbn = AttrListEntry->SegmentReference.LowPart * SectorsPerFrs;
  425. Vcn = Vbn / BootSector->SectorsPerCluster;
  426. SectorOffset = (BYTE)(Vbn % BootSector->SectorsPerCluster);
  427. if(!pNtfsComputeMftLcn(PartitionHandle,Vcn,&Lcn)) {
  428. return(FALSE);
  429. }
  430. printf(".");
  431. //
  432. // Sectors remaining in this frs is initially the whole frs
  433. //
  434. Remaining = SectorsPerFrs;
  435. //
  436. // Change the LCN back into an LBN and add the remainder
  437. // back in to get the sector we want to read. Then store
  438. // this in the next Lcn array slot.
  439. //
  440. Lbn = (Lcn * BootSector->SectorsPerCluster) + SectorOffset;
  441. xStart = Lbn;
  442. xCount = BootSector->SectorsPerCluster - SectorOffset;
  443. if(xCount > Remaining) {
  444. xCount = Remaining;
  445. }
  446. Count = xCount;
  447. while(Remaining -= Count) {
  448. Vbn += Count;
  449. Vcn = Vbn / BootSector->SectorsPerCluster;
  450. if(!pNtfsComputeMftLcn(PartitionHandle,Vcn,&Lcn)) {
  451. return(FALSE);
  452. }
  453. Lbn = Lcn * BootSector->SectorsPerCluster;
  454. Count = BootSector->SectorsPerCluster;
  455. if(Count > Remaining) {
  456. Count = Remaining;
  457. }
  458. //
  459. // Check contiguity
  460. //
  461. if((xStart + xCount) == Lbn) {
  462. xCount += Count;
  463. } else {
  464. MftMappings = realloc(MftMappings,(ArraySize+1)*sizeof(MFT_MAPPING));
  465. if(!MftMappings) {
  466. fprintf(stderr,"\n%s\n",textOOM);
  467. return(FALSE);
  468. }
  469. MftMappings[ArraySize].Start = xStart;
  470. MftMappings[ArraySize].Count = xCount;
  471. ArraySize++;
  472. xStart = Lbn;
  473. xCount = Count;
  474. }
  475. printf(".");
  476. }
  477. MftMappings = realloc(MftMappings,(ArraySize+1)*sizeof(MFT_MAPPING));
  478. if(!MftMappings) {
  479. fprintf(stderr,"\n%s\n",textOOM);
  480. return(FALSE);
  481. }
  482. MftMappings[ArraySize].Start = xStart;
  483. MftMappings[ArraySize].Count = xCount;
  484. ArraySize++;
  485. SegmentsInMft++;
  486. }
  487. } while(AttrListEntry->TypeCode == $DATA);
  488. } else {
  489. printf(".");
  490. }
  491. return(TRUE);
  492. }
  493. BOOL
  494. pNtfsTransferVolumeBitmap(
  495. IN HPARTITION PartitionHandle,
  496. IN PARTITION_IMAGE *PartitionImage,
  497. IN UINT OutputFileHandle
  498. )
  499. {
  500. FPFILE_RECORD_SEGMENT BitmapFrsBuffer;
  501. FPATTRIBUTE_RECORD Record;
  502. BOOL b;
  503. ULONG Frn;
  504. //
  505. // Allocate a scratch buffer for the volume bitmap frs,
  506. // then locate the frs for the volume bitmap and read it in.
  507. //
  508. BitmapFrsBuffer = malloc(SectorsPerFrs * 512);
  509. if(!BitmapFrsBuffer) {
  510. fprintf(stderr,"\n%s\n",textOOM);
  511. return(FALSE);
  512. }
  513. if(!pNtfsReadFrs(PartitionHandle,PartitionImage,BIT_MAP_FILE_NUMBER,BitmapFrsBuffer)) {
  514. free(BitmapFrsBuffer);
  515. return(FALSE);
  516. }
  517. printf(".");
  518. //
  519. // Attempt to locate a $DATA attribute for the volume bitmap.
  520. // If there is none, get the attribute list.
  521. //
  522. Record = pNtfsLocateAttributeRecord(BitmapFrsBuffer,$DATA);
  523. printf(".");
  524. if(!Record) {
  525. b = pNtfsSearchFrsForAttrList(
  526. PartitionHandle,
  527. PartitionImage,
  528. BitmapFrsBuffer,
  529. $DATA,
  530. &Frn
  531. );
  532. if(!b) {
  533. free(BitmapFrsBuffer);
  534. return(FALSE);
  535. }
  536. b = pNtfsReadFrs(PartitionHandle,PartitionImage,Frn,BitmapFrsBuffer);
  537. if(!b) {
  538. free(BitmapFrsBuffer);
  539. return(FALSE);
  540. }
  541. printf(".");
  542. Record = pNtfsLocateAttributeRecord(BitmapFrsBuffer,$DATA);
  543. if(!Record) {
  544. fprintf(stderr,"\n");
  545. fprintf(stderr,textNtfsCorrupt,0);
  546. fprintf(stderr,"\n");
  547. free(BitmapFrsBuffer);
  548. return(FALSE);
  549. }
  550. }
  551. printf(".\n");
  552. b = pNtfsReadWholeAttribute(
  553. PartitionHandle,
  554. PartitionImage,
  555. Record,
  556. NULL,
  557. OutputFileHandle
  558. );
  559. free(BitmapFrsBuffer);
  560. return(b);
  561. }
  562. BOOL
  563. pNtfsProcessVolumeBitmap(
  564. IN OUT PARTITION_IMAGE *PartitionImage,
  565. IN UINT FileHandle
  566. )
  567. {
  568. ULONG LastUsed;
  569. ULONG TotalUsed;
  570. ULONG BaseCluster;
  571. UINT Offset;
  572. UINT Read;
  573. ULONG i;
  574. extern BYTE BitValue[8];
  575. //
  576. // Rewind the file
  577. //
  578. DosSeek(FileHandle,0,DOSSEEK_START);
  579. LastUsed = 0;
  580. TotalUsed = 0;
  581. BaseCluster = 0;
  582. for(i=0; i<PartitionImage->ClusterCount; i++,Offset++) {
  583. //
  584. // Reload bitmap buffer if necessary
  585. //
  586. if(!(i % (512*8))) {
  587. if(_dos_read(FileHandle,IoBuffer,512,&Read) || (Read != 512)) {
  588. fprintf(stderr,"\n%s\n",textFileReadFailed);
  589. return(FALSE);
  590. }
  591. printf(textProcessingNtfsBitmap,100*i/PartitionImage->ClusterCount);
  592. printf("\r");
  593. Offset = 0;
  594. if(i) {
  595. BaseCluster += (512*8);
  596. }
  597. }
  598. if(((FPBYTE)IoBuffer)[Offset/8] & BitValue[Offset%8]) {
  599. TotalUsed++;
  600. LastUsed = i;
  601. }
  602. }
  603. PartitionImage->UsedClusterCount = TotalUsed;
  604. PartitionImage->LastUsedCluster = LastUsed;
  605. //
  606. // Calculate the number of sectors in the bitmap.
  607. // It's impossible for an NTFS drive to have none used since
  608. // all fs data structures are part of clusters, so we don't worry
  609. // about boundary cases.
  610. //
  611. i = (LastUsed / (8*512)) + 1;
  612. //
  613. // Truncate the output file.
  614. //
  615. if((DosSeek(FileHandle,i*512,DOSSEEK_START) != i*512)
  616. || _dos_write(FileHandle,IoBuffer,0,&Read)) {
  617. fprintf(stderr,"\n%s\n",textFileWriteError);
  618. return(FALSE);
  619. }
  620. printf(textProcessingNtfsBitmap,100);
  621. printf("\n");
  622. return(TRUE);
  623. }
  624. BOOL
  625. pNtfsMultiSectorFixup(
  626. IN OUT FPVOID Buffer
  627. )
  628. {
  629. UINT Size,Offset;
  630. FPUINT p,q;
  631. Offset = ((FPMULTI_SECTOR_HEADER)Buffer)->UpdateArrayOfs;
  632. Size = ((FPMULTI_SECTOR_HEADER)Buffer)->UpdateArraySize;
  633. if(!Size) {
  634. fprintf(stderr,"\n");
  635. fprintf(stderr,textNtfsCorrupt,1);
  636. fprintf(stderr,"\n");
  637. return(FALSE);
  638. }
  639. p = (FPUINT)((FPBYTE)Buffer + Offset) + 1;
  640. q = (FPUINT)((FPBYTE)Buffer + SEQUENCE_NUMBER_STRIDE) - 1;
  641. while(--Size) {
  642. *q = *p++;
  643. q = (FPUINT)((FPBYTE)q + SEQUENCE_NUMBER_STRIDE);
  644. }
  645. return(TRUE);
  646. }
  647. FPATTRIBUTE_RECORD
  648. pNtfsLocateAttributeRecord(
  649. IN FPFILE_RECORD_SEGMENT FrsBuffer,
  650. IN ULONG TypeCode
  651. )
  652. {
  653. FPATTRIBUTE_RECORD Attr;
  654. Attr = (FPATTRIBUTE_RECORD)((FPBYTE)FrsBuffer + FrsBuffer->FirstAttribute);
  655. while(Attr->TypeCode != $END) {
  656. if((Attr->TypeCode == TypeCode) && !Attr->NameLength) {
  657. return(Attr);
  658. }
  659. Attr = (FPATTRIBUTE_RECORD)((FPBYTE)Attr + Attr->RecordLength);
  660. }
  661. return(NULL);
  662. }
  663. BOOL
  664. pNtfsReadWholeAttribute(
  665. IN HPARTITION PartitionHandle,
  666. IN PARTITION_IMAGE *PartitionImage,
  667. IN FPATTRIBUTE_RECORD Attribute,
  668. OUT FPVOID Buffer, OPTIONAL
  669. IN UINT OutputFileHandle OPTIONAL
  670. )
  671. {
  672. FPRESIDENT_ATTRIBUTE_FORM Resident;
  673. FPNONRESIDENT_ATTRIBUTE_FORM NonResident;
  674. ULONG ClusterCount;
  675. UINT RunLength;
  676. ULONG Vcn,Lcn,Lbn;
  677. UINT Sectors;
  678. BYTE x;
  679. UINT Written;
  680. ULONG SectorsDone;
  681. ULONG OriginalCount;
  682. if(Attribute->FormCode == RESIDENT_FORM) {
  683. Resident = (FPRESIDENT_ATTRIBUTE_FORM)((FPBYTE)Attribute + offsetof(ATTRIBUTE_RECORD,FormUnion));
  684. if(Buffer) {
  685. if(Resident->ValueLength > ATTR_LIST_BUFFER_SIZE) {
  686. fprintf(stderr,"\n");
  687. fprintf(stderr,textNtfsUnsupportedConfig,3);
  688. fprintf(stderr,"\n");
  689. return(FALSE);
  690. }
  691. memmove(
  692. Buffer,
  693. (FPBYTE)Attribute + Resident->ValueOffset,
  694. (UINT)Resident->ValueLength
  695. );
  696. return(TRUE);
  697. } else {
  698. fprintf(stderr,"\n");
  699. fprintf(stderr,textNtfsUnsupportedConfig,4);
  700. fprintf(stderr,"\n");
  701. return(FALSE);
  702. }
  703. }
  704. NonResident = (FPNONRESIDENT_ATTRIBUTE_FORM)((FPBYTE)Attribute + offsetof(ATTRIBUTE_RECORD,FormUnion));
  705. ClusterCount = NonResident->HighestVcn + 1;
  706. if(Buffer && ((ClusterCount * PartitionImage->SectorsPerCluster * 512) > (ULONG)ATTR_LIST_BUFFER_SIZE)) {
  707. fprintf(stderr,"\n");
  708. fprintf(stderr,textNtfsUnsupportedConfig,5);
  709. fprintf(stderr,"\n");
  710. return(FALSE);
  711. }
  712. Vcn = 0;
  713. if(!Buffer) {
  714. OriginalCount = ClusterCount * PartitionImage->SectorsPerCluster;
  715. SectorsDone = 0;
  716. printf(textNtfsBuildingBitmap,0);
  717. printf("\r");
  718. }
  719. while(ClusterCount) {
  720. pNtfsComputeLcn(Vcn,Attribute,&Lcn,&RunLength);
  721. if(ClusterCount < (ULONG)RunLength) {
  722. RunLength = (UINT)ClusterCount;
  723. }
  724. Sectors = RunLength * PartitionImage->SectorsPerCluster;
  725. Lbn = Lcn * PartitionImage->SectorsPerCluster;
  726. while(Sectors) {
  727. x = (BYTE)((Sectors > 32) ? 32 : Sectors);
  728. if(!ReadPartition(PartitionHandle,Lbn,x,IoBuffer)) {
  729. fprintf(stderr,"\n");
  730. fprintf(stderr,textReadFailedAtSector,Lbn);
  731. fprintf(stderr,"\n");
  732. return(FALSE);
  733. }
  734. if(Buffer) {
  735. memmove(Buffer,IoBuffer,x*512);
  736. (FPBYTE)Buffer += x*512;
  737. } else {
  738. if(_dos_write(OutputFileHandle,IoBuffer,x*512,&Written) || (Written != x*512U)) {
  739. fprintf(stderr,"\n%s\n",textFileWriteError);
  740. return(FALSE);
  741. }
  742. }
  743. Sectors -= x;
  744. Lbn += x;
  745. if(!Buffer) {
  746. SectorsDone += x;
  747. printf(textNtfsBuildingBitmap,100 * SectorsDone / OriginalCount);
  748. printf("\r");
  749. }
  750. }
  751. Vcn += RunLength;
  752. ClusterCount -= RunLength;
  753. }
  754. if(!Buffer) {
  755. printf("\n");
  756. }
  757. return(TRUE);
  758. }
  759. BOOL
  760. pNtfsComputeMftLcn(
  761. IN HPARTITION PartitionHandle,
  762. IN ULONG Vcn,
  763. OUT ULONG *Lcn
  764. )
  765. {
  766. UINT Segment;
  767. FPMFT_MAPPING MftMapping;
  768. BYTE Remaining;
  769. FPBYTE Buffer;
  770. FPATTRIBUTE_RECORD Attribute;
  771. UINT RunLength;
  772. MftMapping = MftMappings;
  773. for(Segment=0; Segment<SegmentsInMft; Segment++) {
  774. Remaining = SectorsPerFrs;
  775. Buffer = (FPBYTE)MftLcnFrsScratchBuffer;
  776. while(Remaining) {
  777. if(!ReadPartition(PartitionHandle,MftMapping->Start,MftMapping->Count,IoBuffer)) {
  778. fprintf(stderr,"\n");
  779. fprintf(stderr,textReadFailedAtSector,MftMapping->Start);
  780. fprintf(stderr,"\n");
  781. return(FALSE);
  782. }
  783. memmove(Buffer,IoBuffer,MftMapping->Count*512);
  784. Remaining -= MftMapping->Count;
  785. Buffer += MftMapping->Count*512;
  786. MftMapping++;
  787. }
  788. if(!pNtfsMultiSectorFixup(MftLcnFrsScratchBuffer)) {
  789. return(FALSE);
  790. }
  791. Attribute = pNtfsLocateAttributeRecord(MftLcnFrsScratchBuffer,$DATA);
  792. if(!Attribute) {
  793. fprintf(stderr,"\n");
  794. fprintf(stderr,textNtfsCorrupt,2);
  795. fprintf(stderr,"\n");
  796. return(FALSE);
  797. }
  798. if(pNtfsComputeLcn(Vcn,Attribute,Lcn,&RunLength)) {
  799. return(TRUE);
  800. }
  801. }
  802. //
  803. // Didn't find it, something is wrong
  804. //
  805. fprintf(stderr,"\n");
  806. fprintf(stderr,textNtfsCorrupt,3);
  807. fprintf(stderr,"\n");
  808. return(FALSE);
  809. }
  810. BOOL
  811. pNtfsComputeLcn(
  812. IN ULONG Vcn,
  813. IN FPATTRIBUTE_RECORD Attribute,
  814. OUT ULONG *Lcn,
  815. OUT UINT *RunLength
  816. )
  817. {
  818. FPNONRESIDENT_ATTRIBUTE_FORM NonResident;
  819. FPBYTE p;
  820. ULONG CurrentLcn,CurrentVcn,NextVcn;
  821. BYTE x1,x2;
  822. //
  823. // Make sure we're non-resident
  824. //
  825. if(Attribute->FormCode == RESIDENT_FORM) {
  826. return(FALSE);
  827. }
  828. //
  829. // Address the nonresident info
  830. //
  831. NonResident = (FPNONRESIDENT_ATTRIBUTE_FORM)((FPBYTE)Attribute + offsetof(ATTRIBUTE_RECORD,FormUnion));
  832. //
  833. // See if the desired VCN is in range
  834. //
  835. if((Vcn > NonResident->HighestVcn) || (Vcn < NonResident->LowestVcn)) {
  836. return(FALSE);
  837. }
  838. p = (FPBYTE)Attribute + NonResident->MappingPairOffset;
  839. CurrentLcn = 0;
  840. CurrentVcn = NonResident->LowestVcn;
  841. //
  842. // The loop condition checks the count byte
  843. //
  844. while(*p) {
  845. CurrentLcn += pNtfsLcnFromMappingPair(p);
  846. NextVcn = CurrentVcn + pNtfsVcnFromMappingPair(p);
  847. if(Vcn < NextVcn) {
  848. //
  849. // Found it.
  850. //
  851. *RunLength = (UINT)(NextVcn - Vcn);
  852. *Lcn = (Vcn - CurrentVcn) + CurrentLcn;
  853. return(TRUE);
  854. }
  855. CurrentVcn = NextVcn;
  856. x1 = *p;
  857. x2 = x1 & (BYTE)0xf;
  858. x1 >>= 4;
  859. p += x1+x2+1;
  860. }
  861. return(FALSE);
  862. }
  863. ULONG
  864. pNtfsLcnFromMappingPair(
  865. IN FPBYTE p
  866. )
  867. {
  868. BYTE v,l;
  869. long x;
  870. v = *p & (BYTE)0xf;
  871. l = (BYTE)(*p >> 4);
  872. if(!l) {
  873. return(0);
  874. }
  875. p += v + l;
  876. x = *(FPCHAR)p;
  877. l--;
  878. p--;
  879. while(l) {
  880. x <<= 8;
  881. x |= *p;
  882. p--;
  883. l--;
  884. }
  885. return(x);
  886. }
  887. ULONG
  888. pNtfsVcnFromMappingPair(
  889. IN FPBYTE p
  890. )
  891. {
  892. BYTE v;
  893. long x;
  894. v = *p & (BYTE)0xf;
  895. if(!v) {
  896. return(0);
  897. }
  898. p += v;
  899. x = *(FPCHAR)p;
  900. v--;
  901. p--;
  902. while(v) {
  903. x <<= 8;
  904. x |= *p;
  905. p--;
  906. v--;
  907. }
  908. return(x);
  909. }
  910. BOOL
  911. pNtfsReadFrs(
  912. IN HPARTITION PartitionHandle,
  913. IN PARTITION_IMAGE *PartitionImage,
  914. IN ULONG FileNumber,
  915. OUT FPVOID Buffer
  916. )
  917. {
  918. if(!pNtfsReadMftSectors(PartitionHandle,PartitionImage,FileNumber*SectorsPerFrs,Buffer)) {
  919. return(FALSE);
  920. }
  921. pNtfsMultiSectorFixup(Buffer);
  922. return(TRUE);
  923. }
  924. BOOL
  925. pNtfsReadMftSectors(
  926. IN HPARTITION PartitionHandle,
  927. IN PARTITION_IMAGE *PartitionImage,
  928. IN ULONG Vbn,
  929. OUT FPBYTE Buffer
  930. )
  931. {
  932. BYTE Remaining;
  933. BYTE Count;
  934. ULONG Vcn;
  935. BYTE r;
  936. ULONG Lcn;
  937. ULONG Lbn;
  938. ULONG NextVbn;
  939. Remaining = SectorsPerFrs;
  940. while(Remaining) {
  941. //
  942. // Get VCN
  943. //
  944. Vcn = Vbn / PartitionImage->SectorsPerCluster;
  945. r = (BYTE)(Vbn % PartitionImage->SectorsPerCluster);
  946. if(!pNtfsComputeMftLcn(PartitionHandle,Vcn,&Lcn)) {
  947. return(FALSE);
  948. }
  949. Lbn = (Lcn * PartitionImage->SectorsPerCluster) + r;
  950. //
  951. // Read in only a single cluster at a time to avoid problems
  952. // with fragmented runs in the mft.
  953. //
  954. if(Remaining > PartitionImage->SectorsPerCluster) {
  955. Count = PartitionImage->SectorsPerCluster;
  956. Remaining -= PartitionImage->SectorsPerCluster;
  957. NextVbn = Vbn + PartitionImage->SectorsPerCluster;
  958. } else {
  959. //
  960. // No need to worry about NextVbn since we'll break out of
  961. // the loop (Remaining will be 0).
  962. //
  963. Count = Remaining;
  964. Remaining = 0;
  965. }
  966. if(!ReadPartition(PartitionHandle,Lbn,Count,IoBuffer)) {
  967. fprintf(stderr,"\n");
  968. fprintf(stderr,textReadFailedAtSector,Lbn);
  969. fprintf(stderr,"\n");
  970. return(FALSE);
  971. }
  972. memmove(Buffer,IoBuffer,Count*512);
  973. Buffer += Count*512;
  974. Vbn = NextVbn;
  975. }
  976. return(TRUE);
  977. }
  978. BOOL
  979. pNtfsSearchFrsForAttrList(
  980. IN HPARTITION PartitionHandle,
  981. IN PARTITION_IMAGE *PartitionImage,
  982. IN FPFILE_RECORD_SEGMENT FrsBuffer,
  983. IN ULONG TypeCode,
  984. OUT ULONG *Frn
  985. )
  986. {
  987. FPATTRIBUTE_RECORD Record;
  988. FPATTRIBUTE_LIST_ENTRY Attribute;
  989. BOOL b;
  990. Record = pNtfsLocateAttributeRecord(FrsBuffer,$ATTRIBUTE_LIST);
  991. if(!Record) {
  992. fprintf(stderr,"\n");
  993. fprintf(stderr,textNtfsCorrupt,4);
  994. fprintf(stderr,"\n");
  995. return(FALSE);
  996. }
  997. //
  998. // Got it, now read the attribute list into the attribute list
  999. // scratch buffer
  1000. //
  1001. b = pNtfsReadWholeAttribute(
  1002. PartitionHandle,
  1003. PartitionImage,
  1004. Record,
  1005. AttrListBuffer,
  1006. 0
  1007. );
  1008. if(!b) {
  1009. return(FALSE);
  1010. }
  1011. Attribute = AttrListBuffer;
  1012. nextrec:
  1013. if(Attribute->TypeCode == TypeCode) {
  1014. *Frn = Attribute->SegmentReference.LowPart;
  1015. return(TRUE);
  1016. }
  1017. if(Attribute->TypeCode == $END) {
  1018. fprintf(stderr,"\n");
  1019. fprintf(stderr,textNtfsCorrupt,5);
  1020. fprintf(stderr,"\n");
  1021. return(FALSE);
  1022. }
  1023. if(!Attribute->Length) {
  1024. fprintf(stderr,"\n");
  1025. fprintf(stderr,textNtfsCorrupt,6);
  1026. fprintf(stderr,"\n");
  1027. return(FALSE);
  1028. }
  1029. Attribute = (FPATTRIBUTE_LIST_ENTRY)((FPBYTE)Attribute + Attribute->Length);
  1030. goto nextrec;
  1031. }