xref: /reactos/modules/rosapps/lib/vfdlib/vfdfat.c (revision d5b576b2)
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 //
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 //
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