xref: /haiku/src/add-ons/kernel/file_systems/fat/mkdos.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2015, François Revol <revol@free.fr>
3  * Copyright (c) 2002 Marcus Overhagen <marcus@overhagen.de>, Haiku project
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include "system_dependencies.h"
10 
11 #define MKDOS
12 #include "mkdos.h"
13 
14 
15 #define WITH_FLOPPY_SUPPORT
16 
17 
18 void PrintUsage();
19 status_t Initialize(int fatbits, const char *device, const char *label,
20 	bool noprompt, bool testmode);
21 status_t parse_initialize_parameters(const char* parameterString,
22 	initialize_parameters& parameters);
23 
24 
25 static void
26 create_volume_label_sector(void *sector, const char *label)
27 {
28 	// create a volume name directory entry in the 512 byte sector
29 	// XXX convert from UTF8, and check for valid characters
30 	// XXX this could be changed to use long file name entrys,
31 	// XXX but the dosfs would have to be updated, too
32 
33 	fatdirent *d = (fatdirent *)sector;
34 	memset(d, 0, sizeof(*d));
35 	memset(d->Name, 0x20, 11);
36 	memcpy(d->Name, label, min_c(11, strlen(label)));
37 	d->Attr = 0x08;
38 }
39 
40 
41 status_t
42 check_volume_name(const char* name)
43 {
44 	if (name == NULL)
45 		return B_BAD_VALUE;
46 	if (strlen(name) > 11)
47 		return B_NAME_TOO_LONG;
48 	if (strchr(name, '/') != NULL)
49 		return B_BAD_VALUE;
50 
51 	return B_OK;
52 }
53 
54 
55 status_t
56 parse_initialize_parameters(const char* parameterString,
57 	initialize_parameters& parameters)
58 {
59 	parameters.flags = 0;
60 	parameters.verbose = false;
61 
62 	void *handle = parse_driver_settings_string(parameterString);
63 	if (handle == NULL)
64 		return B_ERROR;
65 
66 //	if (get_driver_boolean_parameter(handle, "noindex", false, true))
67 //		parameters.flags |= VOLUME_NO_INDICES;
68 	if (get_driver_boolean_parameter(handle, "verbose", false, true))
69 		parameters.verbose = true;
70 
71 	const char *string = get_driver_parameter(handle, "fat",
72 		NULL, NULL);
73 	uint32 fatBits = 0;
74 	if (string != NULL)
75 		fatBits = strtoul(string, NULL, 0);
76 
77 	unload_driver_settings(handle);
78 
79 	if (fatBits != 0 && fatBits != 12 && fatBits != 16 && fatBits != 32) {
80 		dprintf("mkdos error: fat must be 12, 16, or 32 bits\n");
81 		return B_BAD_VALUE;
82 	}
83 
84 	parameters.fatBits = fatBits;
85 
86 	return B_OK;
87 }
88 
89 
90 
91 status_t
92 dosfs_initialize(int fd, partition_id partitionID, const char* name,
93 	const char* parameterString, off_t partitionSize, disk_job_id job)
94 {
95 	dprintf("dosfs_initialize(%d, , '%s', '%s', %" B_PRIdOFF ")\n",
96 		fd, name, parameterString, partitionSize);
97 	if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512
98 		|| sizeof(fsinfosector32) != 512) {
99 		dprintf("dosfs: compilation error: struct alignment wrong\n");
100 		return B_BAD_VALUE;
101 	}
102 
103 	// check name
104 	status_t status = check_volume_name(name);
105 	if (status != B_OK)
106 		return status;
107 
108 	// parse parameters
109 	initialize_parameters parameters;
110 	status = parse_initialize_parameters(parameterString, parameters);
111 	if (status != B_OK)
112 		return status;
113 
114 	update_disk_device_job_progress(job, 0);
115 
116 	int fatbits = parameters.fatBits;
117 	const char *label = name;
118 
119 	if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) {
120 		dprintf("dosfs Error: don't know how to create a %d bit fat\n",fatbits);
121 		return B_ERROR;
122 	}
123 
124 	// initialize the volume
125 	bool isRawDevice;
126 	bool hasBiosGeometry;
127 	bool hasDeviceGeometry;
128 	bool hasPartitionInfo;
129 	device_geometry biosGeometry;
130 	device_geometry deviceGeometry;
131 	partition_info 	partitionInfo;
132 
133 	isRawDevice = 0;//0 != strstr(device, "/raw");
134 	hasBiosGeometry = B_OK == ioctl(fd, B_GET_BIOS_GEOMETRY, &biosGeometry,
135 		sizeof(biosGeometry));
136 	hasDeviceGeometry = B_OK == ioctl(fd, B_GET_GEOMETRY, &deviceGeometry,
137 		sizeof(deviceGeometry));
138 	hasPartitionInfo = B_OK == ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
139 		sizeof(partitionInfo));
140 
141 	if (!isRawDevice && !hasBiosGeometry && !hasDeviceGeometry
142 		&& !hasPartitionInfo) {
143 		isRawDevice = true;
144 	}
145 
146 	if (hasBiosGeometry) {
147 		dprintf("dosfs: bios geometry: %" B_PRIu32 " heads, "
148 			"%" B_PRIu32 " cylinders, "
149 			"%" B_PRIu32 " sectors/track, "
150 			"%" B_PRIu32 " bytes/sector\n",
151 			biosGeometry.head_count,
152 			biosGeometry.cylinder_count,
153 			biosGeometry.sectors_per_track,
154 			biosGeometry.bytes_per_sector);
155 	}
156 	if (hasDeviceGeometry) {
157 		dprintf("dosfs: device geometry: %" B_PRIu32 " heads, "
158 			"%" B_PRIu32 " cylinders, "
159 			"%" B_PRIu32 " sectors/track, "
160 			"%" B_PRIu32 " bytes/sector\n",
161 			deviceGeometry.head_count,
162 			deviceGeometry.cylinder_count,
163 			deviceGeometry.sectors_per_track,
164 			deviceGeometry.bytes_per_sector);
165 	}
166 	if (hasPartitionInfo) {
167 		dprintf("dosfs: partition info: start at %" B_PRIdOFF " bytes "
168 			"(%" B_PRIdOFF " sectors), "
169 			"%" B_PRIdOFF " KB, "
170 			"%" B_PRIdOFF " MB, "
171 			"%" B_PRIdOFF " GB\n",
172 			partitionInfo.offset,
173 			partitionInfo.offset / 512,
174 			partitionInfo.offset / 1024,
175 			partitionInfo.offset / (1024 * 1024),
176 			partitionInfo.offset / (1024 * 1024 * 1024));
177 		dprintf("dosfs: partition info: size %" B_PRIdOFF " bytes, "
178 			"%" B_PRIdOFF " KB, "
179 			"%" B_PRIdOFF " MB, "
180 			"%" B_PRIdOFF " GB\n",
181 			partitionInfo.size,
182 			partitionInfo.size / 1024,
183 			partitionInfo.size / (1024 * 1024),
184 			partitionInfo.size / (1024 * 1024 * 1024));
185 	}
186 
187 	if (!isRawDevice && !hasPartitionInfo)
188 		dprintf("dosfs Warning: couldn't get partition information\n");
189 
190 	if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512)
191 		||	(hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) {
192 		dprintf("dosfs Error: geometry block size not 512 bytes\n");
193 		return B_ERROR;
194 	} else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) {
195 		dprintf("dosfs: partition logical block size is not 512, "
196 			"it's %" B_PRId32 " bytes\n",
197 			partitionInfo.logical_block_size);
198 	}
199 
200 	if (hasDeviceGeometry && deviceGeometry.read_only) {
201 		dprintf("dosfs Error: this is a read-only device\n");
202 		return B_ERROR;
203 	}
204 	if (hasDeviceGeometry && deviceGeometry.write_once) {
205 		dprintf("dosfs Error: this is a write-once device\n");
206 		return B_ERROR;
207 	}
208 	uint64 size = 0;
209 
210 	if (hasPartitionInfo) {
211 		size = partitionInfo.size;
212 	} else if (hasDeviceGeometry) {
213 		size = uint64(deviceGeometry.bytes_per_sector)
214 			* deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count
215 			* deviceGeometry.head_count;
216 	} else if (hasBiosGeometry) {
217 		size = uint64(biosGeometry.bytes_per_sector)
218 			* biosGeometry.sectors_per_track * biosGeometry.cylinder_count
219 			* biosGeometry.head_count;
220 	} else {
221 		// maybe it's just a file
222 		struct stat stat;
223 		if (fstat(fd, &stat) < 0) {
224 			dprintf("dosfs Error: couldn't get device partition or geometry "
225 				"information, nor size\n");
226 			return B_ERROR;
227 		}
228 		size = stat.st_size;
229 	}
230 
231 	dprintf("dosfs: size = %" B_PRIu64 " bytes "
232 		"(%" B_PRIu64 " sectors), "
233 		"%" B_PRIu64 " KB, "
234 		"%" B_PRIu64 " MB, "
235 		"%" B_PRIu64 " GB\n",
236 		size,
237 		size / 512,
238 		size / 1024,
239 		size / (1024 * 1024),
240 		size / (1024 * 1024 * 1024));
241 
242 	if (fatbits == 0) {
243 		//auto determine fat type
244 		if (isRawDevice && size <= FLOPPY_MAX_SIZE
245 			&& (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) {
246 			fatbits = 12;
247 		} else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) {
248 			fatbits = 16;
249 		} else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) {
250 			fatbits = 32;
251 		}
252 	}
253 
254 	if (fatbits == 0) {
255 		dprintf("dosfs Error: device too large for 32 bit fat\n");
256 		return B_ERROR;
257 	}
258 
259 	int sectorPerCluster;
260 
261 	sectorPerCluster = 0;
262 	if (fatbits == 12) {
263 		sectorPerCluster = 0;
264 		if (size <= 4182016LL)
265 			sectorPerCluster = 2;	// XXX don't know the correct value
266 		if (size <= 2091008LL)
267 			sectorPerCluster = 1;	// XXX don't know the correct value
268 	} else if (fatbits == 16) {
269 		// special BAD_CLUSTER value is 0xFFF7,
270 		// but this should work anyway, since space required by
271 		// two FATs will make maximum cluster count smaller.
272 		// at least, this is what I think *should* happen
273 		sectorPerCluster = 0;				//larger than 2 GB must fail
274 		if (size <= (2048 * 1024 * 1024LL))	// up to 2GB, use 32k clusters
275 			sectorPerCluster = 64;
276 		if (size <= (1024 * 1024 * 1024LL))	// up to 1GB, use 16k clusters
277 			sectorPerCluster = 32;
278 		if (size <= (512 * 1024 * 1024LL))	// up to 512MB, use 8k clusters
279 			sectorPerCluster = 16;
280 		if (size <= (256 * 1024 * 1024LL))	// up to 256MB, use 4k clusters
281 			sectorPerCluster = 8;
282 		if (size <= (128 * 1024 * 1024LL))	// up to 128MB, use 2k clusters
283 			sectorPerCluster = 4;
284 		if (size <= (16 * 1024 * 1024LL))	// up to 16MB, use 2k clusters
285 			sectorPerCluster = 2;
286 		if (size <= 4182016LL)				// smaller than fat32 must fail
287 			sectorPerCluster = 0;
288 	} else if (fatbits == 32) {
289 		sectorPerCluster = 64;				// default is 32k clusters
290 		if (size <= (32 * 1024 * 1024 * 1024LL)) {
291 			// up to 32GB, use 16k clusters
292 			sectorPerCluster = 32;
293 		}
294 		if (size <= (16 * 1024 * 1024 * 1024LL)) {
295 			// up to 16GB, use 8k clusters
296 			sectorPerCluster = 16;
297 		}
298 		if (size <= (8 * 1024 * 1024 * 1024LL)) {
299 			// up to 8GB, use 4k clusters
300 			sectorPerCluster = 8;
301 		}
302 		if (size <= (532480 * 512LL)) {
303 			// up to 260 MB, use 0.5k clusters
304 			sectorPerCluster = 1;
305 		}
306 		if (size <= (66600 * 512LL)) {
307 			// smaller than 32.5 MB must fail
308 			sectorPerCluster = 0;
309 		}
310 	}
311 
312 	if (sectorPerCluster == 0) {
313 		dprintf("dosfs Error: failed to determine sector per cluster value, "
314 			"partition too large for %d bit fat\n",fatbits);
315 		return B_ERROR;
316 	}
317 
318 	int reservedSectorCount = 0; // avoid compiler warning
319 	int rootEntryCount = 0; // avoid compiler warning
320 	int numFATs;
321 	int sectorSize;
322 	uint8 biosDriveId;
323 
324 	// get bios drive-id, or use 0x80
325 	if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId,
326 		sizeof(biosDriveId))) {
327 		biosDriveId = 0x80;
328 	} else {
329 		dprintf("dosfs: bios drive id: 0x%02x\n", (int)biosDriveId);
330 	}
331 
332 	// default parameters for the bootsector
333 	numFATs = 2;
334 	sectorSize = 512;
335 	if (fatbits == 12 || fatbits == 16)
336 		reservedSectorCount = 1;
337 	if (fatbits == 32)
338 		reservedSectorCount = 32;
339 	if (fatbits == 12)
340 		rootEntryCount = 128; // XXX don't know the correct value
341 	if (fatbits == 16)
342 		rootEntryCount = 512;
343 	if (fatbits == 32)
344 		rootEntryCount = 0;
345 
346 	// Determine FATSize
347 	// calculation done as MS recommends
348 	uint64 dskSize = size / sectorSize;
349 	uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1))
350 		/ sectorSize;
351 	uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
352 	uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs;
353 	if (fatbits == 32)
354 		tmpVal2 = tmpVal2 / 2;
355 	uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
356 	// FATSize should now contain the size of *one* FAT, measured in sectors
357 	// RootDirSectors should now contain the size of the fat12/16 root
358 	// directory, measured in sectors
359 
360 	dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits,
361 		sectorPerCluster * 512);
362 	dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize);
363 	dprintf("dosfs: disk label: %s\n", label);
364 
365 
366 
367 	if (status < B_OK) {
368 		dprintf("dosfs: Initializing volume failed: %s\n", strerror(status));
369 		return status;
370 	}
371 
372 	char bootsector[512];
373 	memset(bootsector,0x00,512);
374 	memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp));
375 	memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode));
376 
377 	if (fatbits == 32) {
378 		bootsector32 *bs = (bootsector32 *)bootsector;
379 		uint16 temp16;
380 		uint32 temp32;
381 		memcpy(bs->BS_OEMName,"Haiku   ",8);
382 		bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
383 		bs->BPB_SecPerClus = sectorPerCluster;
384 		bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
385 		bs->BPB_NumFATs = numFATs;
386 		bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
387 		bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0);
388 		bs->BPB_Media = 0xF8;
389 		bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0);
390 		temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
391 		bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
392 		temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
393 		bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
394 		temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
395 		bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
396 		temp32 = size / 512;
397 		bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
398 		bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize);
399 		bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0);
400 		bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0);
401 		bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER);
402 		bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM);
403 		bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM);
404 		memset(bs->BPB_Reserved,0,12);
405 		bs->BS_DrvNum = biosDriveId;
406 		bs->BS_Reserved1 = 0x00;
407 		bs->BS_BootSig = 0x29;
408 		*(uint32*)bs->BS_VolID = (uint32)system_time();
409 		memset(bs->BS_VolLab, 0x20, 11);
410 		memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
411 		memcpy(bs->BS_FilSysType,"FAT32   ",8);
412 		bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
413 	} else {
414 		bootsector1216 *bs = (bootsector1216 *)bootsector;
415 		uint16 temp16;
416 		uint32 temp32;
417 		uint32 sectorcount = size / 512;
418 		memcpy(bs->BS_OEMName, "Haiku   ", 8);
419 		bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
420 		bs->BPB_SecPerClus = sectorPerCluster;
421 		bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
422 		bs->BPB_NumFATs = numFATs;
423 		bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
424 		temp16 = (sectorcount <= 65535) ? sectorcount : 0;
425 		bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16);
426 		bs->BPB_Media = 0xF8;
427 		bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize);
428 		temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
429 		bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
430 		temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
431 		bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
432 		temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
433 		bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
434 		temp32 = (sectorcount <= 65535) ? 0 : sectorcount;
435 		bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
436 		bs->BS_DrvNum = biosDriveId;
437 		bs->BS_Reserved1 = 0x00;
438 		bs->BS_BootSig = 0x29;
439 		*(uint32*)bs->BS_VolID = (uint32)system_time();
440 		memset(bs->BS_VolLab, 0x20, 11);
441 		memcpy(bs->BS_VolLab, label, min_c(11, strlen(label)));
442 		memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12   " : "FAT16   ",8);
443 		bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
444 	}
445 
446 	// Disk layout:
447 	// 0) reserved sectors, this includes the bootsector, fsinfosector and
448 	//    bootsector backup
449 	// 1) FAT
450 	// 2) root directory (not on fat32)
451 	// 3) file & directory data
452 
453 	ssize_t written;
454 
455 	// initialize everything with zero first
456 	// avoid doing 512 byte writes here, they are slow
457 	dprintf("dosfs: Writing FAT\n");
458 	char * zerobuffer = (char *)malloc(65536);
459 	memset(zerobuffer,0,65536);
460 	int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize)
461 		+ rootDirSectors);
462 	int64 pos = 0;
463 	while (bytes_to_write > 0) {
464 		ssize_t writesize = min_c(bytes_to_write, 65536);
465 		written = write_pos(fd, pos, zerobuffer, writesize);
466 		if (written != writesize) {
467 			dprintf("dosfs Error: write error near sector %" B_PRId64 "\n",
468 				pos / 512);
469 			free(zerobuffer);
470 			return B_ERROR;
471 		}
472 		bytes_to_write -= writesize;
473 		pos += writesize;
474 	}
475 	free(zerobuffer);
476 
477 	//write boot sector
478 	dprintf("dosfs: Writing boot block\n");
479 	written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
480 	if (written != 512) {
481 		dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
482 		return B_ERROR;
483 	}
484 
485 	if (fatbits == 32) {
486 		written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
487 		if (written != 512) {
488 			dprintf("dosfs Error: write error at sector %d\n",
489 				BACKUP_SECTOR_NUM);
490 			return B_ERROR;
491 		}
492 	}
493 
494 	//write first fat sector
495 	dprintf("dosfs: Writing first FAT sector\n");
496 	uint8 sec[512];
497 	memset(sec,0,512);
498 	if (fatbits == 12) {
499 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
500 		//FAT[1] contains EOF marker
501 		sec[0] = 0xF8;
502 		sec[1] = 0xFF;
503 		sec[2] = 0xFF;
504 	} else if (fatbits == 16) {
505 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
506 		sec[0] = 0xF8;
507 		sec[1] = 0xFF;
508 		//FAT[1] contains EOF marker
509 		sec[2] = 0xFF;
510 		sec[3] = 0xFF;
511 	} else if (fatbits == 32) {
512 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
513 		sec[0] = 0xF8;
514 		sec[1] = 0xFF;
515 		sec[2] = 0xFF;
516 		sec[3] = 0xFF;
517 		//FAT[1] contains EOF marker
518 		sec[4] = 0xFF;
519 		sec[5] = 0xFF;
520 		sec[6] = 0xFF;
521 		sec[7] = 0x0F;
522 		//FAT[2] contains EOF marker, used to terminate root directory
523 		sec[8] = 0xFF;
524 		sec[9] = 0xFF;
525 		sec[10] = 0xFF;
526 		sec[11] = 0x0F;
527 	}
528 	written = write_pos(fd, reservedSectorCount * 512, sec, 512);
529 	if (written != 512) {
530 		dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
531 		return B_ERROR;
532 	}
533 	if (numFATs > 1) {
534 		written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
535 		if (written != 512) {
536 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
537 				reservedSectorCount + FATSize);
538 			return B_ERROR;
539 		}
540 	}
541 
542 	//write fsinfo sector
543 	if (fatbits == 32) {
544 		dprintf("dosfs: Writing boot info\n");
545 		//calculate total sector count first
546 		uint64 free_count = size / 512;
547 		//now account for already by metadata used sectors
548 		free_count -= reservedSectorCount + (numFATs * FATSize)
549 			+ rootDirSectors;
550 		//convert from sector to clustercount
551 		free_count /= sectorPerCluster;
552 		//and account for 1 already used cluster of root directory
553 		free_count -= 1;
554 		fsinfosector32 fsinfosector;
555 		memset(&fsinfosector,0x00,512);
556 		fsinfosector.FSI_LeadSig 	= B_HOST_TO_LENDIAN_INT32(0x41615252);
557 		fsinfosector.FSI_StrucSig 	= B_HOST_TO_LENDIAN_INT32(0x61417272);
558 		fsinfosector.FSI_Free_Count
559 			= B_HOST_TO_LENDIAN_INT32((uint32)free_count);
560 		fsinfosector.FSI_Nxt_Free 	= B_HOST_TO_LENDIAN_INT32(3);
561 		fsinfosector.FSI_TrailSig 	= B_HOST_TO_LENDIAN_INT32(0xAA550000);
562 		written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
563 		if (written != 512) {
564 			dprintf("dosfs Error: write error at sector %d\n",
565 				FSINFO_SECTOR_NUM);
566 			return B_ERROR;
567 		}
568 	}
569 
570 	//write volume label into root directory
571 	dprintf("dosfs: Writing root directory\n");
572 	if (fatbits == 12 || fatbits == 16) {
573 		uint8 data[512];
574 		memset(data, 0, 512);
575 		create_volume_label_sector(data, label);
576 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
577 		written = write_pos(fd, rootDirSector * 512, data, 512);
578 		if (written != 512) {
579 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
580 				rootDirSector);
581 			return B_ERROR;
582 		}
583 	} else if (fatbits == 32) {
584 		int size = 512 * sectorPerCluster;
585 		uint8 *cluster = (uint8*)malloc(size);
586 		memset(cluster, 0, size);
587 		create_volume_label_sector(cluster, label);
588 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize)
589 			+ rootDirSectors;
590 		written = write_pos(fd, rootDirSector * 512, cluster, size);
591 		free(cluster);
592 		if (written != size) {
593 			dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
594 				rootDirSector);
595 			return B_ERROR;
596 		}
597 	}
598 
599 	ioctl(fd, B_FLUSH_DRIVE_CACHE);
600 
601 
602 
603 	// rescan partition
604 	status = scan_partition(partitionID);
605 	if (status != B_OK)
606 		return status;
607 
608 	update_disk_device_job_progress(job, 1);
609 
610 	// print some info, if desired
611 	if (parameters.verbose) {
612 //		disk_super_block super = volume.SuperBlock();
613 
614 		dprintf("dosfs: Disk was initialized successfully.\n");
615 /*
616 		dprintf("\tname: \"%s\"\n", super.name);
617 		dprintf("\tnum blocks: %" B_PRIdOFF "\n", super.NumBlocks());
618 		dprintf("\tused blocks: %" B_PRIdOFF "\n", super.UsedBlocks());
619 		dprintf("\tblock size: %u bytes\n", (unsigned)super.BlockSize());
620 		dprintf("\tnum allocation groups: %d\n",
621 			(int)super.AllocationGroups());
622 		dprintf("\tallocation group size: %ld blocks\n",
623 			1L << super.AllocationGroupShift());
624 		dprintf("\tlog size: %u blocks\n", super.log_blocks.Length());
625 */
626 	}
627 
628 	return B_OK;
629 }
630 
631 
632 status_t
633 dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
634 	uint32 blockSize, disk_job_id job)
635 {
636 	if (blockSize == 0)
637 		return B_BAD_VALUE;
638 
639 	update_disk_device_job_progress(job, 0.0);
640 
641 	// just overwrite the superblock
642 	// XXX: we might want to keep the loader part ?
643 	char bootsector[512];
644 	memset(bootsector,0x00,512);
645 
646 	if (write_pos(fd, 512, bootsector, sizeof(bootsector)) < 0)
647 		return errno;
648 
649 	update_disk_device_job_progress(job, 1.0);
650 
651 	return B_OK;
652 }
653 
654 
655 //	#pragma mark -
656 
657 
658 #if 0 // For testing standalone builds
659 int
660 main(int argc, char *argv[])
661 {
662 	if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512
663 		|| sizeof(fsinfosector32) != 512) {
664 		dprintf("compilation error: struct alignment wrong\n");
665 		return 1;
666 	}
667 
668 	const char *device = NULL;
669 	const char *label = NULL;
670 	bool noprompt = false;
671 	bool test = false;
672 	int fat = 0;
673 
674 	while (1) {
675 		int c;
676 		int option_index = 0;
677 		static struct option long_options[] =
678 		{
679 		 	{"noprompt", no_argument, 0, 'n'},
680 			{"test", no_argument, 0, 't'},
681 			{"fat", required_argument, 0, 'f'},
682 			{0, 0, 0, 0}
683 		};
684 
685 		c = getopt_long (argc, argv, "ntf:", long_options, &option_index);
686 		if (c == -1)
687 			break;
688 
689 		switch (c) {
690 			case 'n':
691 				noprompt = true;
692 		 		break;
693 
694 			case 't':
695 				test = true;
696 				break;
697 
698 			case 'f':
699 				fat = strtol(optarg, NULL, 10);
700 				if (fat == 0)
701 					fat = -1;
702 				break;
703 
704 			default:
705 		        printf("\n");
706 				PrintUsage();
707 				return 1;
708 		}
709 	}
710 
711 	if (optind < argc)
712 		device = argv[optind];
713 	if ((optind + 1) < argc)
714 		label = argv[optind + 1];
715 
716 	if (fat != 0 && fat != 12 && fat != 16 && fat != 32) {
717 		printf("mkdos error: fat must be 12, 16, or 32 bits\n");
718 		PrintUsage();
719 		return 1;
720 	}
721 
722 	if (device == NULL) {
723 		printf("mkdos error: you must specify a device or partition or image\n");
724         printf("             such as /dev/disk/ide/ata/1/master/0/0_0\n");
725 		PrintUsage();
726 		return 1;
727 	}
728 
729 	if (label == NULL) {
730 		label = "no name";
731 	}
732 
733 	if (noprompt)
734 		printf("will not prompt for confirmation\n");
735 
736 	if (test)
737 		printf("test mode enabled (no writes will occur)\n");
738 
739 	status_t s;
740 	s = Initialize(fat, device, label, noprompt, test);
741 
742 	if (s != 0) {
743 		printf("Initializing failed!\n");
744 	}
745 
746 	return (s == B_OK) ? 0 : 1;
747 }
748 #endif
749