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