xref: /haiku/src/add-ons/kernel/file_systems/fat/mkdos.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 /*
2  * Copyright 2015, François Revol <revol@free.fr>
3  * Copyright (c) 2002 Marcus Overhagen <marcus@overhagen.de>, Haiku project
4  * Copyright 2024, Haiku, Inc. All rights reserved.
5  *
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #define MKDOS
11 #include "mkdos.h"
12 
13 #ifdef FS_SHELL
14 #include "fssh_api_wrapper.h"
15 #else
16 #include <stdlib.h>
17 
18 #include <ByteOrder.h>
19 #include <KernelExport.h>
20 #include <driver_settings.h>
21 #endif // !FS_SHELL
22 
23 #include "dosfs.h"
24 #include "support.h"
25 
26 #ifdef USER
27 #define dprintf(x...) ;
28 #endif
29 #define WITH_FLOPPY_SUPPORT
30 
31 
32 static void
33 create_volume_label_sector(void *sector, const char *label)
34 {
35 	// create a volume name directory entry in the 512 byte sector
36 	// XXX convert from UTF8, and check for valid characters
37 	// XXX this could be changed to use long file name entrys,
38 	// XXX but the dosfs would have to be updated, too
39 
40 	struct direntry* d = (struct direntry*)sector;
41 	memset(d, 0, sizeof(*d));
42 	memset(d->deName, 0x20, 11);
43 	memcpy(d->deName, label, min_c(11, strlen(label)));
44 	d->deAttributes = 0x08;
45 }
46 
47 
48 status_t
49 parse_initialize_parameters(const char* parameterString,
50 	initialize_parameters& parameters)
51 {
52 	parameters.flags = 0;
53 	parameters.verbose = false;
54 
55 	void *handle = parse_driver_settings_string(parameterString);
56 	if (handle == NULL)
57 		return B_ERROR;
58 
59 	if (get_driver_boolean_parameter(handle, "verbose", false, true))
60 		parameters.verbose = true;
61 
62 	const char *string = get_driver_parameter(handle, "fat",
63 		NULL, NULL);
64 	uint32 fatBits = 0;
65 	if (string != NULL)
66 		fatBits = strtoul(string, NULL, 0);
67 
68 	unload_driver_settings(handle);
69 
70 	if (fatBits != 0 && fatBits != 12 && fatBits != 16 && fatBits != 32) {
71 		dprintf("mkdos error: fat must be 12, 16, or 32 bits\n");
72 		return B_BAD_VALUE;
73 	}
74 
75 	parameters.fatBits = fatBits;
76 
77 	return B_OK;
78 }
79 
80 
81 status_t
82 _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char* parameterString,
83 	off_t partitionSize, disk_job_id job)
84 {
85 	dprintf("dosfs_initialize(%d, , '%s', '%s', %" B_PRIdOFF ")\n",	fd, name, parameterString,
86 		partitionSize);
87 	if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512
88 		|| sizeof(fsinfosector32) != 512) {
89 		dprintf("dosfs: compilation error: struct alignment wrong\n");
90 		return B_BAD_VALUE;
91 	}
92 
93 	// parse parameters
94 	initialize_parameters parameters;
95 	status_t status = parse_initialize_parameters(parameterString, parameters);
96 	if (status != B_OK)
97 		return status;
98 
99 	update_disk_device_job_progress(job, 0);
100 
101 	int fatbits = parameters.fatBits;
102 	char label[LABEL_CSTRING];
103 	strlcpy(label, name, LABEL_CSTRING);
104 	status = label_to_fat(label);
105 	if (status != B_OK)
106 		return status;
107 
108 	if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) {
109 		dprintf("dosfs Error: don't know how to create a %d bit fat\n", fatbits);
110 		return B_ERROR;
111 	}
112 
113 	// initialize the volume
114 	bool isRawDevice;
115 	bool hasBiosGeometry;
116 	bool hasDeviceGeometry;
117 	bool hasPartitionInfo;
118 	device_geometry biosGeometry;
119 	device_geometry deviceGeometry;
120 	partition_info 	partitionInfo;
121 
122 	isRawDevice = 0;//0 != strstr(device, "/raw");
123 	hasBiosGeometry = B_OK == ioctl(fd, B_GET_BIOS_GEOMETRY, &biosGeometry,
124 		sizeof(biosGeometry));
125 	hasDeviceGeometry = B_OK == ioctl(fd, B_GET_GEOMETRY, &deviceGeometry,
126 		sizeof(deviceGeometry));
127 	hasPartitionInfo = B_OK == ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
128 		sizeof(partitionInfo));
129 
130 	if (!isRawDevice && !hasBiosGeometry && !hasDeviceGeometry
131 		&& !hasPartitionInfo) {
132 		isRawDevice = true;
133 	}
134 
135 	if (hasBiosGeometry) {
136 		dprintf("dosfs: bios geometry: %" B_PRIu32 " heads, "
137 			"%" B_PRIu32 " cylinders, "
138 			"%" B_PRIu32 " sectors/track, "
139 			"%" B_PRIu32 " bytes/sector\n",
140 			biosGeometry.head_count,
141 			biosGeometry.cylinder_count,
142 			biosGeometry.sectors_per_track,
143 			biosGeometry.bytes_per_sector);
144 	}
145 	if (hasDeviceGeometry) {
146 		dprintf("dosfs: device geometry: %" B_PRIu32 " heads, "
147 			"%" B_PRIu32 " cylinders, "
148 			"%" B_PRIu32 " sectors/track, "
149 			"%" B_PRIu32 " bytes/sector\n",
150 			deviceGeometry.head_count,
151 			deviceGeometry.cylinder_count,
152 			deviceGeometry.sectors_per_track,
153 			deviceGeometry.bytes_per_sector);
154 	}
155 	if (hasPartitionInfo) {
156 		dprintf("dosfs: partition info: start at %" B_PRIdOFF " bytes "
157 			"(%" B_PRIdOFF " sectors), "
158 			"%" B_PRIdOFF " KB, "
159 			"%" B_PRIdOFF " MB, "
160 			"%" B_PRIdOFF " GB\n",
161 			partitionInfo.offset,
162 			partitionInfo.offset / 512,
163 			partitionInfo.offset / 1024,
164 			partitionInfo.offset / (1024 * 1024),
165 			partitionInfo.offset / (1024 * 1024 * 1024));
166 		dprintf("dosfs: partition info: size %" B_PRIdOFF " bytes, "
167 			"%" B_PRIdOFF " KB, "
168 			"%" B_PRIdOFF " MB, "
169 			"%" B_PRIdOFF " GB\n",
170 			partitionInfo.size,
171 			partitionInfo.size / 1024,
172 			partitionInfo.size / (1024 * 1024),
173 			partitionInfo.size / (1024 * 1024 * 1024));
174 	}
175 
176 	if (!isRawDevice && !hasPartitionInfo)
177 		dprintf("dosfs Warning: couldn't get partition information\n");
178 
179 	if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512)
180 		||	(hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) {
181 		dprintf("dosfs Error: geometry block size not 512 bytes\n");
182 		return B_ERROR;
183 	} else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) {
184 		dprintf("dosfs: partition logical block size is not 512, "
185 			"it's %" B_PRId32 " bytes\n",
186 			partitionInfo.logical_block_size);
187 	}
188 
189 	if (hasDeviceGeometry && deviceGeometry.read_only) {
190 		dprintf("dosfs Error: this is a read-only device\n");
191 		return B_ERROR;
192 	}
193 	if (hasDeviceGeometry && deviceGeometry.write_once) {
194 		dprintf("dosfs Error: this is a write-once device\n");
195 		return B_ERROR;
196 	}
197 	uint64 size = 0;
198 
199 	if (hasPartitionInfo) {
200 		size = partitionInfo.size;
201 	} else if (hasDeviceGeometry) {
202 		size = uint64(deviceGeometry.bytes_per_sector)
203 			* deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count
204 			* deviceGeometry.head_count;
205 	} else if (hasBiosGeometry) {
206 		size = uint64(biosGeometry.bytes_per_sector)
207 			* biosGeometry.sectors_per_track * biosGeometry.cylinder_count
208 			* biosGeometry.head_count;
209 	} else {
210 		// maybe it's just a file
211 		struct stat stat;
212 		if (fstat(fd, &stat) < 0) {
213 			dprintf("dosfs Error: couldn't get device partition or geometry "
214 				"information, nor size\n");
215 			return B_ERROR;
216 		}
217 		size = stat.st_size;
218 	}
219 
220 	dprintf("dosfs: size = %" B_PRIu64 " bytes "
221 		"(%" B_PRIu64 " sectors), "
222 		"%" B_PRIu64 " KB, "
223 		"%" B_PRIu64 " MB, "
224 		"%" B_PRIu64 " GB\n",
225 		size,
226 		size / 512,
227 		size / 1024,
228 		size / (1024 * 1024),
229 		size / (1024 * 1024 * 1024));
230 
231 	if (fatbits == 0) {
232 		//auto determine fat type
233 		if (isRawDevice && size <= FLOPPY_MAX_SIZE
234 			&& (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) {
235 			fatbits = 12;
236 		} else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) {
237 			fatbits = 16;
238 		} else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) {
239 			fatbits = 32;
240 		}
241 	}
242 
243 	if (fatbits == 0) {
244 		dprintf("dosfs Error: device too large for 32 bit fat\n");
245 		return B_ERROR;
246 	}
247 
248 	int sectorPerCluster;
249 
250 	sectorPerCluster = 0;
251 	if (fatbits == 12) {
252 		sectorPerCluster = 0;
253 		if (size < 16777216LL)
254 			sectorPerCluster = 8;
255 		if (size <= 2949120)
256 			sectorPerCluster = 2;
257 		if (size <= 1474560)
258 			sectorPerCluster = 1;
259 		if (size <= 737280) {
260 			// We follow Microsoft guidance in increasing cluster size for the smallest disks.
261 			// The idea was probably to keep the FAT from taking up a too much of a small disk.
262 			sectorPerCluster = 2;
263 		}
264 	} else if (fatbits == 16) {
265 		sectorPerCluster = 0;				//larger than 2 GB must fail
266 		if (size <= (2048 * 1024 * 1024LL))	// up to 2GB, use 32k clusters
267 			sectorPerCluster = 64;
268 		if (size <= (1024 * 1024 * 1024LL))	// up to 1GB, use 16k clusters
269 			sectorPerCluster = 32;
270 		if (size <= (512 * 1024 * 1024LL))	// up to 512MB, use 8k clusters
271 			sectorPerCluster = 16;
272 		if (size <= (256 * 1024 * 1024LL))	// up to 256MB, use 4k clusters
273 			sectorPerCluster = 8;
274 		if (size <= (128 * 1024 * 1024LL))	// up to 128MB, use 2k clusters
275 			sectorPerCluster = 4;
276 		if (size <= (16 * 1024 * 1024LL))	// up to 16MB, use 1k clusters
277 			sectorPerCluster = 2;
278 		if (size <= 4182016LL)				// smaller than 4.1 MB must fail
279 			sectorPerCluster = 0;
280 	} else if (fatbits == 32) {
281 		sectorPerCluster = 64;				// default is 32k clusters
282 		if (size <= (32 * 1024 * 1024 * 1024LL)) {
283 			// up to 32GB, use 16k clusters
284 			sectorPerCluster = 32;
285 		}
286 		if (size <= (16 * 1024 * 1024 * 1024LL)) {
287 			// up to 16GB, use 8k clusters
288 			sectorPerCluster = 16;
289 		}
290 		if (size <= (8 * 1024 * 1024 * 1024LL)) {
291 			// up to 8GB, use 4k clusters
292 			sectorPerCluster = 8;
293 		}
294 		if (size <= (532480 * 512LL)) {
295 			// up to 260 MB, use 0.5k clusters
296 			sectorPerCluster = 1;
297 		}
298 		if (size <= (66600 * 512LL)) {
299 			// smaller than 32.5 MB must fail
300 			sectorPerCluster = 0;
301 		}
302 	}
303 
304 	if (sectorPerCluster == 0) {
305 		dprintf("dosfs Error: failed to determine sector per cluster value, "
306 			"partition too large for %d bit fat\n",fatbits);
307 		return B_ERROR;
308 	}
309 
310 	int reservedSectorCount = 0; // avoid compiler warning
311 	int rootEntryCount = 0; // avoid compiler warning
312 	int numFATs;
313 	int sectorSize;
314 	uint8 biosDriveId;
315 
316 	// get bios drive-id, or use 0x80
317 	if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId,
318 		sizeof(biosDriveId))) {
319 		biosDriveId = 0x80;
320 	} else {
321 		dprintf("dosfs: bios drive id: 0x%02x\n", (int)biosDriveId);
322 	}
323 
324 	// default parameters for the bootsector
325 	numFATs = 2;
326 	sectorSize = 512;
327 	if (fatbits == 12 || fatbits == 16)
328 		reservedSectorCount = 1;
329 	if (fatbits == 32)
330 		reservedSectorCount = 32;
331 	if (fatbits == 12)
332 		rootEntryCount = 512;
333 	if (fatbits == 16)
334 		rootEntryCount = 512;
335 	if (fatbits == 32)
336 		rootEntryCount = 0;
337 
338 	// Determine FATSize
339 	// calculation done as MS recommends
340 	uint64 dskSize = size / sectorSize;
341 	uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1))
342 		/ sectorSize;
343 	uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
344 	uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs;
345 	if (fatbits == 32)
346 		tmpVal2 = tmpVal2 / 2;
347 	uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
348 	// FATSize should now contain the size of *one* FAT, measured in sectors
349 	// RootDirSectors should now contain the size of the fat12/16 root
350 	// directory, measured in sectors
351 
352 	// Now that clusters can be counted, verify cluster count is compatible with the FAT type
353 	uint64 sectorCount = size / 512;
354 	uint64 dataSec = sectorCount - (reservedSectorCount + (numFATs * FATSize) + rootDirSectors);
355 	uint64 clusterCount = dataSec / sectorPerCluster;
356 	if (fatbits == 12 && clusterCount > FAT12_MAX_CLUSTER_COUNT) {
357 		dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT12 limit.\n", clusterCount);
358 		return B_BAD_VALUE;
359 	}
360 	if (fatbits == 16 && clusterCount > FAT16_MAX_CLUSTER_COUNT) {
361 		dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT16 limit.\n", clusterCount);
362 		return B_BAD_VALUE;
363 	}
364 	if (fatbits == 32 && clusterCount > FAT32_MAX_CLUSTER_COUNT) {
365 		dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT32 limit.\n", clusterCount);
366 		return B_BAD_VALUE;
367 	}
368 
369 	dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits,	sectorPerCluster * 512);
370 	dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize);
371 	dprintf("dosfs: disk label: %s\n", label);
372 
373 
374 
375 	if (status < B_OK) {
376 		dprintf("dosfs: Initializing volume failed: %s\n", strerror(status));
377 		return status;
378 	}
379 
380 	char bootsector[512];
381 	memset(bootsector,0x00,512);
382 	memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp));
383 	memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode));
384 
385 	if (fatbits == 32) {
386 		bootsector32 *bs = (bootsector32 *)bootsector;
387 		uint16 temp16;
388 		uint32 temp32;
389 		memcpy(bs->BS_OEMName,"Haiku   ",8);
390 		bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
391 		bs->BPB_SecPerClus = sectorPerCluster;
392 		bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
393 		bs->BPB_NumFATs = numFATs;
394 		bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
395 		bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0);
396 		bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
397 		bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0);
398 		temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
399 		bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
400 		temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
401 		bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
402 		temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
403 		bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
404 		bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(sectorCount);
405 		bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize);
406 		bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0);
407 		bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0);
408 		bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER);
409 		bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM);
410 		bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM);
411 		memset(bs->BPB_Reserved,0,12);
412 		bs->BS_DrvNum = biosDriveId;
413 		bs->BS_Reserved1 = 0x00;
414 		bs->BS_BootSig = 0x29;
415 		uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time());
416 		memcpy(bs->BS_VolID, &volID, 4);
417 		memset(bs->BS_VolLab, 0x20, 11);
418 		memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
419 		memcpy(bs->BS_FilSysType,"FAT32   ",8);
420 		bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
421 	} else {
422 		bootsector1216 *bs = (bootsector1216 *)bootsector;
423 		uint16 temp16;
424 		uint32 temp32;
425 		memcpy(bs->BS_OEMName, "Haiku   ", 8);
426 		bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
427 		bs->BPB_SecPerClus = sectorPerCluster;
428 		bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
429 		bs->BPB_NumFATs = numFATs;
430 		bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
431 		temp16 = (sectorCount <= 65535) ? sectorCount : 0;
432 		bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16);
433 		bs->BPB_Media = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
434 		bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize);
435 		temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
436 		bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
437 		temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
438 		bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
439 		temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
440 		bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
441 		temp32 = (sectorCount <= 65535) ? 0 : sectorCount;
442 		bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
443 		bs->BS_DrvNum = biosDriveId;
444 		bs->BS_Reserved1 = 0x00;
445 		bs->BS_BootSig = 0x29;
446 		uint32 volID = B_HOST_TO_LENDIAN_INT32(system_time());
447 		memcpy(bs->BS_VolID, &volID, 4);
448 		memset(bs->BS_VolLab, 0x20, 11);
449 		memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
450 		memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12   " : "FAT16   ",8);
451 		bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
452 	}
453 
454 	// Disk layout:
455 	// 0) reserved sectors, this includes the bootsector, fsinfosector and
456 	//    bootsector backup
457 	// 1) FAT
458 	// 2) root directory (not on fat32)
459 	// 3) file & directory data
460 
461 	ssize_t written;
462 
463 	// initialize everything with zero first
464 	// avoid doing 512 byte writes here, they are slow
465 	dprintf("dosfs: Writing FAT\n");
466 	char * zerobuffer = (char *)malloc(65536);
467 	memset(zerobuffer,0,65536);
468 	int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize)
469 		+ rootDirSectors);
470 	int64 pos = 0;
471 	while (bytes_to_write > 0) {
472 		ssize_t writesize = min_c(bytes_to_write, 65536);
473 		written = write_pos(fd, pos, zerobuffer, writesize);
474 		if (written != writesize) {
475 			dprintf("dosfs Error: write error near sector %" B_PRId64 "\n", pos / 512);
476 			free(zerobuffer);
477 			return B_ERROR;
478 		}
479 		bytes_to_write -= writesize;
480 		pos += writesize;
481 	}
482 	free(zerobuffer);
483 
484 	//write boot sector
485 	dprintf("dosfs: Writing boot block\n");
486 	written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
487 	if (written != 512) {
488 		dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
489 		return B_ERROR;
490 	}
491 
492 	if (fatbits == 32) {
493 		written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
494 		if (written != 512) {
495 			dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
496 			return B_ERROR;
497 		}
498 	}
499 
500 	//write first fat sector
501 	dprintf("dosfs: Writing first FAT sector\n");
502 	uint8 sec[512];
503 	memset(sec,0,512);
504 	if (fatbits == 12) {
505 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
506 		//FAT[1] contains EOF marker
507 		sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
508 		sec[1] = 0xFF;
509 		sec[2] = 0xFF;
510 	} else if (fatbits == 16) {
511 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
512 		sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
513 		sec[1] = 0xFF;
514 		//FAT[1] contains EOF marker
515 		sec[2] = 0xFF;
516 		sec[3] = 0xFF;
517 	} else if (fatbits == 32) {
518 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
519 		sec[0] = hasDeviceGeometry && deviceGeometry.removable ? 0xF0 : 0xF8;
520 		sec[1] = 0xFF;
521 		sec[2] = 0xFF;
522 		sec[3] = 0xFF;
523 		//FAT[1] contains EOF marker
524 		sec[4] = 0xFF;
525 		sec[5] = 0xFF;
526 		sec[6] = 0xFF;
527 		sec[7] = 0x0F;
528 		//FAT[2] contains EOF marker, used to terminate root directory
529 		sec[8] = 0xFF;
530 		sec[9] = 0xFF;
531 		sec[10] = 0xFF;
532 		sec[11] = 0x0F;
533 	}
534 	written = write_pos(fd, reservedSectorCount * 512, sec, 512);
535 	if (written != 512) {
536 		dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
537 		return B_ERROR;
538 	}
539 	if (numFATs > 1) {
540 		written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
541 		if (written != 512) {
542 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
543 				reservedSectorCount + FATSize);
544 			return B_ERROR;
545 		}
546 	}
547 
548 	//write fsinfo sector
549 	if (fatbits == 32) {
550 		dprintf("dosfs: Writing boot info\n");
551 		// account for 1 already used cluster of root directory
552 		uint64 free_count = clusterCount - 1;
553 		fsinfosector32 fsinfosector;
554 		memset(&fsinfosector,0x00,512);
555 		fsinfosector.FSI_LeadSig 	= B_HOST_TO_LENDIAN_INT32(0x41615252);
556 		fsinfosector.FSI_StrucSig 	= B_HOST_TO_LENDIAN_INT32(0x61417272);
557 		fsinfosector.FSI_Free_Count
558 			= B_HOST_TO_LENDIAN_INT32((uint32)free_count);
559 		fsinfosector.FSI_Nxt_Free 	= B_HOST_TO_LENDIAN_INT32(3);
560 		fsinfosector.FSI_TrailSig 	= B_HOST_TO_LENDIAN_INT32(0xAA550000);
561 		written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
562 		if (written != 512) {
563 			dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
564 			return B_ERROR;
565 		}
566 	}
567 
568 	//write volume label into root directory
569 	dprintf("dosfs: Writing root directory\n");
570 	if (fatbits == 12 || fatbits == 16) {
571 		uint8 data[512];
572 		memset(data, 0, 512);
573 		create_volume_label_sector(data, label);
574 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
575 		written = write_pos(fd, rootDirSector * 512, data, 512);
576 		if (written != 512) {
577 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
578 				rootDirSector);
579 			return B_ERROR;
580 		}
581 	} else if (fatbits == 32) {
582 		int size = 512 * sectorPerCluster;
583 		uint8 *cluster = (uint8*)malloc(size);
584 		memset(cluster, 0, size);
585 		create_volume_label_sector(cluster, label);
586 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize)
587 			+ rootDirSectors;
588 		written = write_pos(fd, rootDirSector * 512, cluster, size);
589 		free(cluster);
590 		if (written != size) {
591 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", rootDirSector);
592 			return B_ERROR;
593 		}
594 	}
595 
596 	ioctl(fd, B_FLUSH_DRIVE_CACHE);
597 
598 
599 
600 	// rescan partition
601 	status = scan_partition(partitionID);
602 	if (status != B_OK)
603 		return status;
604 
605 	update_disk_device_job_progress(job, 1);
606 
607 	// print some info, if desired
608 	if (parameters.verbose) {
609 
610 		dprintf("dosfs: Disk was initialized successfully.\n");
611 	}
612 
613 	return B_OK;
614 }
615 
616 
617 status_t
618 _dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, uint32 blockSize,
619 	disk_job_id job)
620 {
621 	if (blockSize == 0)
622 		return B_BAD_VALUE;
623 
624 	update_disk_device_job_progress(job, 0.0);
625 
626 	// just overwrite the superblock
627 	// XXX: we might want to keep the loader part ?
628 	char bootsector[512];
629 	memset(bootsector,0x00,512);
630 
631 	if (write_pos(fd, 512, bootsector, sizeof(bootsector)) < 0)
632 		return errno;
633 
634 	update_disk_device_job_progress(job, 1.0);
635 
636 	return B_OK;
637 }
638