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