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