1 /*
2 vfdfat.c
3
4 Virtual Floppy Drive for Windows
5 Driver control library
6 Formats the image with FAT12
7
8 Copyright (C) 2003-2005 Ken Kato
9 */
10
11 #ifdef __cplusplus
12 #pragma message(__FILE__": Compiled as C++ for testing purpose.")
13 #endif // __cplusplus
14
15 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
17
18 #include "vfdtypes.h"
19 #include "vfdio.h"
20 #include "vfdlib.h"
21 #include "vfdver.h"
22
23 #pragma pack(1)
24 //
25 // BIOS parameter block
26 //
27 typedef struct _DOS_BPB
28 {
29 USHORT BytesPerSector;
30 UCHAR SectorsPerCluster;
31 USHORT ReservedSectors;
32 UCHAR NumberOfFATs;
33 USHORT RootEntries;
34 USHORT SmallSectors;
35 UCHAR MediaDescriptor;
36 USHORT SectorsPerFAT;
37 USHORT SectorsPerTrack;
38 USHORT NumberOfHeads;
39 ULONG HiddenSectors;
40 ULONG LargeSectors;
41 }
42 DOS_BPB, *PDOS_BPB;
43
44 //
45 // Extended BIOS parameter block for FAT12/16/HUGE
46 //
47 typedef struct _EXBPB
48 {
49 UCHAR PhysicalDriveNumber;
50 UCHAR Reserved;
51 UCHAR BootSignature;
52 ULONG VolumeSerialNumber;
53 CHAR VolumeLabel[11];
54 CHAR FileSystemType[8];
55 }
56 EXBPB, *PEXBPB;
57
58 //
59 // Partition Boot Record
60 //
61 typedef struct _DOS_PBR { // Partition Boot Record
62 UCHAR jump[3]; // Jump Instruction (E9 or EB, xx, 90)
63 CHAR oemid[8]; // OEM ID (OS type)
64 DOS_BPB bpb; // BIOS parameter block
65 EXBPB exbpb; // Extended BIOS parameter block
66 }
67 DOS_PBR, *PDOS_PBR;
68
69 #pragma pack()
70
71 #define FAT_DIR_ENTRY_SIZE 32
72
73 // We need to have the 0xeb and 0x90 in the jump code
74 // because the file system recognizer checks these values
75 #define VFD_JUMP_CODE "\xeb\x3c\x90"
76 #define VFD_OEM_NAME "VFD" VFD_DRIVER_VERSION_STR " "
77 #define VFD_VOLUME_LABEL "NO NAME "
78 #define VFD_FILESYSTEM "FAT12 "
79
80 //
81 // Select DOS BPB parameters from media size
82 //
SelectDosBpb(USHORT nSectors)83 static const DOS_BPB *SelectDosBpb(
84 USHORT nSectors)
85 {
86 static const DOS_BPB bpb_tbl[] = {
87 // b/s s/c r fat root sec desc s/f s/t h
88 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 320, 0xFE, 1, 8, 1, 0, 0}, // 160KB 5.25"
89 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 360, 0xFC, 1, 9, 1, 0, 0}, // 180KB 5.25"
90 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 640, 0xFF, 1, 8, 2, 0, 0}, // 320KB 5.25"
91 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 720, 0xFD, 2, 9, 2, 0, 0}, // 360KB 5.25"
92 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1280, 0xFB, 2, 8, 2, 0, 0}, // 640KB 5.25" / 3.5"
93 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1440, 0xF9, 3, 9, 2, 0, 0}, // 720KB 5.25" / 3.5"
94 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1640, 0xF9, 3, 10, 2, 0, 0}, // 820KB 3.5"
95 {VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 2400, 0xF9, 7, 15, 2, 0, 0}, // 1.20MB 5.25" / 3.5"
96 {VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 2880, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB 3.5"
97 {VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 3360, 0xF0, 10, 21, 2, 0, 0}, // 1.68MB 3.5"
98 {VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 3444, 0xF0, 10, 21, 2, 0, 0}, // 1.72MB 3.5"
99 {VFD_BYTES_PER_SECTOR, 2, 1, 2, 240, 5760, 0xF0, 9, 36, 2, 0, 0}, // 2.88MB 3.5"
100 };
101
102 int i;
103
104 for (i = 0; i < sizeof(bpb_tbl) / sizeof(bpb_tbl[0]); i++) {
105 if (nSectors == bpb_tbl[i].SmallSectors) {
106 return &bpb_tbl[i];
107 }
108 }
109
110 return NULL;
111 }
112
113 //
114 // Format the buffer with FAT12
115 //
FormatBufferFat(PUCHAR pBuffer,ULONG nSectors)116 DWORD FormatBufferFat(
117 PUCHAR pBuffer,
118 ULONG nSectors)
119 {
120 const DOS_BPB *bpb; // BIOS Parameter Block
121 PDOS_PBR pbr; // Partition Boot Record
122 PUCHAR fat; // File Allocation Table
123 USHORT idx;
124
125 VFDTRACE(0,
126 ("[VFD] VfdFormatImage - IN\n"));
127
128 //
129 // Select DOS BPB parameters from media size
130 //
131 bpb = SelectDosBpb((USHORT)nSectors);
132
133 if (!bpb) {
134 VFDTRACE(0,
135 ("[VFD] Unsupported media size %lu\n",
136 nSectors));
137 return ERROR_INVALID_PARAMETER;
138 }
139
140 //
141 // Initialize the whole area with the fill data
142 //
143 FillMemory(pBuffer,
144 VFD_SECTOR_TO_BYTE(nSectors),
145 VFD_FORMAT_FILL_DATA);
146
147 //
148 // Make up the FAT boot record
149 //
150 ZeroMemory(pBuffer, VFD_BYTES_PER_SECTOR);
151
152 pbr = (PDOS_PBR)pBuffer;
153
154 CopyMemory(pbr->jump, VFD_JUMP_CODE, sizeof(pbr->jump));
155 CopyMemory(pbr->oemid, VFD_OEM_NAME, sizeof(pbr->oemid));
156 CopyMemory(&pbr->bpb, bpb, sizeof(pbr->bpb));
157
158 // Make up the extended BPB
159
160 pbr->exbpb.BootSignature = 0x29;
161
162 // use the tick count as the volume serial number
163 pbr->exbpb.VolumeSerialNumber = GetTickCount();
164
165 CopyMemory(pbr->exbpb.VolumeLabel,
166 VFD_VOLUME_LABEL, sizeof(pbr->exbpb.VolumeLabel));
167
168 CopyMemory(pbr->exbpb.FileSystemType,
169 VFD_FILESYSTEM, sizeof(pbr->exbpb.FileSystemType));
170
171 // Set the boot record signature
172
173 *(pBuffer + VFD_BYTES_PER_SECTOR - 2) = 0x55;
174 *(pBuffer + VFD_BYTES_PER_SECTOR - 1) = 0xaa;
175
176 //
177 // Clear FAT areas
178 //
179 fat = pBuffer + VFD_SECTOR_TO_BYTE(bpb->ReservedSectors);
180
181 ZeroMemory(
182 fat,
183 VFD_SECTOR_TO_BYTE(bpb->SectorsPerFAT * bpb->NumberOfFATs));
184
185 //
186 // Make up FAT entries for the root directory
187 //
188 for (idx = 0; idx < bpb->NumberOfFATs; idx++) {
189 *fat = bpb->MediaDescriptor;
190 *(fat + 1) = 0xff;
191 *(fat + 2) = 0xff;
192
193 fat += VFD_SECTOR_TO_BYTE(bpb->SectorsPerFAT);
194 }
195
196 //
197 // Clear root directory entries
198 //
199 ZeroMemory(fat, bpb->RootEntries * FAT_DIR_ENTRY_SIZE);
200
201 VFDTRACE(0,
202 ("[VFD] VfdFormatImage - OUT\n"));
203
204 return ERROR_SUCCESS;
205 }
206