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.

406 lines
10 KiB

  1. #include "imagpart.h"
  2. //
  3. // FAT boot sector.
  4. //
  5. #pragma pack(1)
  6. typedef struct FAT_BOOT_SECTOR {
  7. BYTE Jump[3]; // offset = 0x00 0
  8. UCHAR Oem[8]; // offset = 0x03 3
  9. USHORT BytesPerSector; // offset = 0x0b 11
  10. BYTE SectorsPerCluster; // offset = 0x0d 13
  11. USHORT ReservedSectors; // offset = 0x0e 14
  12. BYTE Fats; // offset = 0x10 16
  13. USHORT RootEntries; // offset = 0x11 17
  14. USHORT Sectors; // offset = 0x13 19
  15. BYTE Media; // offset = 0x15 21
  16. USHORT SectorsPerFat; // offset = 0x16 22
  17. USHORT SectorsPerTrack; // offset = 0x18 24
  18. USHORT Heads; // offset = 0x1a 26
  19. ULONG HiddenSectors; // offset = 0x1c 28
  20. ULONG LargeSectors; // offset = 0x20 32
  21. BYTE PhysicalDriveNumber; // offset = 0x24 36
  22. BYTE Reserved; // offset = 0x25 37
  23. BYTE Signature; // offset = 0x26 38
  24. ULONG Id; // offset = 0x27 39
  25. UCHAR VolumeLabel[11]; // offset = 0x2B 43
  26. UCHAR SystemId[8]; // offset = 0x36 54
  27. BYTE BootStrap[510-62]; // offset = 0x3e 62
  28. BYTE AA55Signature[2]; // offset = 0x1fe 510
  29. } FAT_BOOT_SECTOR,_far *FPFAT_BOOT_SECTOR;
  30. #pragma pack()
  31. typedef enum {
  32. Fat12,
  33. Fat16,
  34. Fat32
  35. } FatSize;
  36. FatSize
  37. pFatDetermineFatSize(
  38. IN FPFAT_BOOT_SECTOR BootSector
  39. );
  40. ULONG
  41. pFatClusterCount(
  42. IN FPFAT_BOOT_SECTOR BootSector
  43. );
  44. ULONG
  45. pFatFirstClusterSector(
  46. IN FPFAT_BOOT_SECTOR BootSector
  47. );
  48. ULONG
  49. pFatSectorsPerFat(
  50. IN FPFAT_BOOT_SECTOR BootSector
  51. );
  52. BOOL
  53. FatIsFat(
  54. IN HPARTITION PartitionHandle
  55. )
  56. {
  57. FPFAT_BOOT_SECTOR BootSector;
  58. if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
  59. return(FALSE);
  60. }
  61. BootSector = IoBuffer;
  62. if(BootSector->Sectors) {
  63. BootSector->LargeSectors = 0;
  64. }
  65. //
  66. // Check various fields for permissible values.
  67. //
  68. if((BootSector->Jump[0] != 0x49) // Fujitsu FMR
  69. && (BootSector->Jump[0] != 0xe9)
  70. && (BootSector->Jump[0] != 0xeb)) {
  71. return(FALSE);
  72. }
  73. if(BootSector->BytesPerSector != 512) {
  74. return(FALSE);
  75. }
  76. if((BootSector->SectorsPerCluster != 1)
  77. && (BootSector->SectorsPerCluster != 2)
  78. && (BootSector->SectorsPerCluster != 4)
  79. && (BootSector->SectorsPerCluster != 8)
  80. && (BootSector->SectorsPerCluster != 16)
  81. && (BootSector->SectorsPerCluster != 32)
  82. && (BootSector->SectorsPerCluster != 64)
  83. && (BootSector->SectorsPerCluster != 128)) {
  84. return(FALSE);
  85. }
  86. if(!BootSector->ReservedSectors || !BootSector->Fats) {
  87. return(FALSE);
  88. }
  89. if(!BootSector->Sectors && !BootSector->LargeSectors) {
  90. return(FALSE);
  91. }
  92. if((BootSector->Media != 0x00) // FMR (formatted by OS/2)
  93. && (BootSector->Media != 0x01) // FMR (floppy, formatted by DOS)
  94. && (BootSector->Media != 0xf0)
  95. && (BootSector->Media != 0xf8)
  96. && (BootSector->Media != 0xf9)
  97. && (BootSector->Media != 0xfa) // FMR
  98. && (BootSector->Media != 0xfb)
  99. && (BootSector->Media != 0xfc)
  100. && (BootSector->Media != 0xfd)
  101. && (BootSector->Media != 0xfe)
  102. && (BootSector->Media != 0xff)) {
  103. return(FALSE);
  104. }
  105. if(BootSector->SectorsPerFat && !BootSector->RootEntries) {
  106. return(FALSE);
  107. }
  108. return(TRUE);
  109. }
  110. BOOL
  111. FatInitializeVolumeData(
  112. IN HPARTITION PartitionHandle,
  113. OUT ULONG *TotalSectorCount,
  114. OUT ULONG *NonClusterSectors,
  115. OUT ULONG *ClusterCount,
  116. OUT BYTE *SectorsPerCluster
  117. )
  118. {
  119. FPFAT_BOOT_SECTOR BootSector;
  120. if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
  121. fprintf(stderr,"\n");
  122. fprintf(stderr,textReadFailedAtSector,0L);
  123. fprintf(stderr,"\n");
  124. return(FALSE);
  125. }
  126. BootSector = IoBuffer;
  127. *TotalSectorCount = BootSector->Sectors
  128. ? (ULONG)BootSector->Sectors
  129. : BootSector->LargeSectors;
  130. *ClusterCount = pFatClusterCount(BootSector);
  131. *NonClusterSectors = pFatFirstClusterSector(BootSector);
  132. *SectorsPerCluster = BootSector->SectorsPerCluster;
  133. return(TRUE);
  134. }
  135. BOOL
  136. FatBuildClusterBitmap(
  137. IN HPARTITION PartitionHandle,
  138. IN UINT FileHandle,
  139. IN OUT PARTITION_IMAGE *PartitionImage
  140. )
  141. {
  142. FPFAT_BOOT_SECTOR BootSector;
  143. FatSize fatsize;
  144. ULONG CurrentFatSectorBase;
  145. ULONG FatSectorsLeft;
  146. ULONG CurrentCluster;
  147. ULONG SectorsPerFat;
  148. BYTE c;
  149. USHORT ClusterLimit;
  150. USHORT i;
  151. USHORT x1;
  152. ULONG x2;
  153. printf(textScanningFat,0L);
  154. printf("\r");
  155. if(!ReadPartition(PartitionHandle,0,1,IoBuffer)) {
  156. fprintf(stderr,"\n");
  157. fprintf(stderr,textReadFailedAtSector,0L);
  158. fprintf(stderr,"\n");
  159. return(FALSE);
  160. }
  161. BootSector = IoBuffer;
  162. fatsize = pFatDetermineFatSize(BootSector);
  163. CurrentFatSectorBase = BootSector->ReservedSectors;
  164. SectorsPerFat = pFatSectorsPerFat(BootSector);
  165. FatSectorsLeft = SectorsPerFat;
  166. CurrentCluster = 0;
  167. InitClusterBuffer((FPBYTE)IoBuffer + (3*512),FileHandle);
  168. while(CurrentCluster < PartitionImage->ClusterCount) {
  169. //
  170. // Read next block of fat sectors. Deal with 3 at a time so
  171. // we never get partial 12-bit fat entries.
  172. //
  173. c = 3;
  174. if((ULONG)c > FatSectorsLeft) {
  175. c = (BYTE)FatSectorsLeft;
  176. }
  177. if(!ReadPartition(PartitionHandle,CurrentFatSectorBase,c,IoBuffer)) {
  178. fprintf(stderr,"\n");
  179. fprintf(stderr,textReadFailedAtSector,CurrentFatSectorBase);
  180. fprintf(stderr,"\n");
  181. return(FALSE);
  182. }
  183. //
  184. // Figure out how many clusters are described by the 3 sectors
  185. // of the FAT we just read in
  186. //
  187. switch(fatsize) {
  188. case Fat12:
  189. ClusterLimit = 1024;
  190. break;
  191. case Fat16:
  192. ClusterLimit = 768;
  193. break;
  194. case Fat32:
  195. ClusterLimit = 384;
  196. break;
  197. }
  198. if((CurrentCluster + ClusterLimit) > PartitionImage->ClusterCount) {
  199. ClusterLimit = (USHORT)(PartitionImage->ClusterCount - CurrentCluster);
  200. }
  201. //
  202. // Fat values:
  203. //
  204. // 0 - free cluster
  205. // 1 - (unused)
  206. // [ffff]ff0 - [ffff]ff6 - (reserved)
  207. // [ffff]ff7 - bad cluster
  208. // [ffff]ff8 - [ffff]fff - last cluster of file
  209. //
  210. // All other values - used cluster
  211. //
  212. switch(fatsize) {
  213. case Fat12:
  214. for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
  215. x1 = *(FPUSHORT)((FPBYTE)IoBuffer + (3 * i / 2));
  216. if(i & 1) {
  217. x1 >>= 4;
  218. } else {
  219. x1 &= 0xfffU;
  220. }
  221. if((((x1 > 1) && (x1 <= 0xfefU)) || (x1 >= 0xff8U)) && (CurrentCluster >= 2)) {
  222. PartitionImage->LastUsedCluster = CurrentCluster-2;
  223. PartitionImage->UsedClusterCount++;
  224. if(!MarkClusterUsed(CurrentCluster-2)) {
  225. return(FALSE);
  226. }
  227. }
  228. }
  229. break;
  230. case Fat16:
  231. for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
  232. x1 = ((FPUSHORT)IoBuffer)[i];
  233. if((((x1 > 1) && (x1 <= 0xffefU)) || (x1 >= 0xfff8U)) && (CurrentCluster >= 2)) {
  234. PartitionImage->LastUsedCluster = CurrentCluster-2;
  235. PartitionImage->UsedClusterCount++;
  236. if(!MarkClusterUsed(CurrentCluster-2)) {
  237. return(FALSE);
  238. }
  239. }
  240. }
  241. break;
  242. case Fat32:
  243. for(i=0; i<ClusterLimit; i++,CurrentCluster++) {
  244. x2 = ((FPULONG)IoBuffer)[i] & 0xfffffffU;
  245. if((((x2 > 1) && (x2 <= 0xfffffefUL)) || (x2 >= 0xffffff8UL)) && (CurrentCluster >= 2)) {
  246. PartitionImage->LastUsedCluster = CurrentCluster-2;
  247. PartitionImage->UsedClusterCount++;
  248. if(!MarkClusterUsed(CurrentCluster-2)) {
  249. return(FALSE);
  250. }
  251. }
  252. }
  253. break;
  254. }
  255. CurrentFatSectorBase += c;
  256. FatSectorsLeft -= c;
  257. printf(textScanningFat,100 * (SectorsPerFat - FatSectorsLeft) / SectorsPerFat);
  258. printf("\r");
  259. }
  260. printf("\n");
  261. if(!FlushClusterBuffer()) {
  262. return(FALSE);
  263. }
  264. return(TRUE);
  265. }
  266. FatSize
  267. pFatDetermineFatSize(
  268. IN FPFAT_BOOT_SECTOR BootSector
  269. )
  270. {
  271. //
  272. // For fat32 the # of root dir entries in the bpb is 0.
  273. //
  274. if(!BootSector->SectorsPerFat) {
  275. return(Fat32);
  276. }
  277. //
  278. // See whether we overflow a 12-bit fat and return result.
  279. //
  280. return((pFatClusterCount(BootSector) < 4087L) ? Fat12 : Fat16);
  281. }
  282. ULONG
  283. pFatClusterCount(
  284. IN FPFAT_BOOT_SECTOR BootSector
  285. )
  286. {
  287. ULONG s;
  288. //
  289. // Calculate the number of sectors that are in the data area,
  290. // which is the size of the volume minus the number of sectors
  291. // that are not in the data area.
  292. //
  293. s = BootSector->Sectors ? (ULONG)BootSector->Sectors : BootSector->LargeSectors;
  294. s -= pFatFirstClusterSector(BootSector);
  295. return(s / BootSector->SectorsPerCluster);
  296. }
  297. ULONG
  298. pFatFirstClusterSector(
  299. IN FPFAT_BOOT_SECTOR BootSector
  300. )
  301. {
  302. ULONG s;
  303. //
  304. // Calculate the number of sectors that are not
  305. // part of the data area. This includes reserved sectors,
  306. // sectors used for the fats, and in the non-fat32 case,
  307. // sectors used for the root directory.
  308. //
  309. // Note that for fat32 the # of root dir entries in the bpb is 0.
  310. //
  311. s = BootSector->ReservedSectors;
  312. s += BootSector->Fats * pFatSectorsPerFat(BootSector);
  313. s += BootSector->RootEntries / 16;
  314. return(s);
  315. }
  316. ULONG
  317. pFatSectorsPerFat(
  318. IN FPFAT_BOOT_SECTOR BootSector
  319. )
  320. {
  321. ULONG SectorsPerFat;
  322. SectorsPerFat = BootSector->SectorsPerFat
  323. ? (ULONG)BootSector->SectorsPerFat
  324. : *(FPULONG)((FPBYTE)BootSector + 0x24); // large sectors per fat
  325. return(SectorsPerFat);
  326. }