xref: /haiku/src/add-ons/kernel/file_systems/fat/mkdos.cpp (revision 427edfcf0ddc74fc461c9355484d33fd4b027b70)
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 			free(zerobuffer);
436 			return B_ERROR;
437 		}
438 		bytes_to_write -= writesize;
439 		pos += writesize;
440 	}
441 	free(zerobuffer);
442 
443 	//write boot sector
444 	dprintf("dosfs: Writing boot block\n");
445 	written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
446 	if (written != 512) {
447 		dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
448 		return B_ERROR;
449 	}
450 
451 	if (fatbits == 32) {
452 		written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
453 		if (written != 512) {
454 			dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
455 			return B_ERROR;
456 		}
457 	}
458 
459 	//write first fat sector
460 	dprintf("dosfs: Writing first FAT sector\n");
461 	uint8 sec[512];
462 	memset(sec,0,512);
463 	if (fatbits == 12) {
464 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
465 		//FAT[1] contains EOF marker
466 		sec[0] = 0xF8;
467 		sec[1] = 0xFF;
468 		sec[2] = 0xFF;
469 	} else if (fatbits == 16) {
470 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
471 		sec[0] = 0xF8;
472 		sec[1] = 0xFF;
473 		//FAT[1] contains EOF marker
474 		sec[2] = 0xFF;
475 		sec[3] = 0xFF;
476 	} else if (fatbits == 32) {
477 		//FAT[0] contains media byte in lower 8 bits, all other bits set to 1
478 		sec[0] = 0xF8;
479 		sec[1] = 0xFF;
480 		sec[2] = 0xFF;
481 		sec[3] = 0xFF;
482 		//FAT[1] contains EOF marker
483 		sec[4] = 0xFF;
484 		sec[5] = 0xFF;
485 		sec[6] = 0xFF;
486 		sec[7] = 0x0F;
487 		//FAT[2] contains EOF marker, used to terminate root directory
488 		sec[8] = 0xFF;
489 		sec[9] = 0xFF;
490 		sec[10] = 0xFF;
491 		sec[11] = 0x0F;
492 	}
493 	written = write_pos(fd, reservedSectorCount * 512, sec, 512);
494 	if (written != 512) {
495 		dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
496 		return B_ERROR;
497 	}
498 	if (numFATs > 1) {
499 		written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
500 		if (written != 512) {
501 			dprintf("dosfs Error: write error at sector %ld\n", reservedSectorCount + FATSize);
502 			return B_ERROR;
503 		}
504 	}
505 
506 	//write fsinfo sector
507 	if (fatbits == 32) {
508 		dprintf("dosfs: Writing boot info\n");
509 		//calculate total sector count first
510 		uint64 free_count = size / 512;
511 		//now account for already by metadata used sectors
512 		free_count -= reservedSectorCount + (numFATs * FATSize) + rootDirSectors;
513 		//convert from sector to clustercount
514 		free_count /= sectorPerCluster;
515 		//and account for 1 already used cluster of root directory
516 		free_count -= 1;
517 		fsinfosector32 fsinfosector;
518 		memset(&fsinfosector,0x00,512);
519 		fsinfosector.FSI_LeadSig 	= B_HOST_TO_LENDIAN_INT32(0x41615252);
520 		fsinfosector.FSI_StrucSig 	= B_HOST_TO_LENDIAN_INT32(0x61417272);
521 		fsinfosector.FSI_Free_Count = B_HOST_TO_LENDIAN_INT32((uint32)free_count);
522 		fsinfosector.FSI_Nxt_Free 	= B_HOST_TO_LENDIAN_INT32(3);
523 		fsinfosector.FSI_TrailSig 	= B_HOST_TO_LENDIAN_INT32(0xAA550000);
524 		written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
525 		if (written != 512) {
526 			dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
527 			return B_ERROR;
528 		}
529 	}
530 
531 	//write volume label into root directory
532 	dprintf("dosfs: Writing root directory\n");
533 	if (fatbits == 12 || fatbits == 16) {
534 		uint8 data[512];
535 		memset(data, 0, 512);
536 		CreateVolumeLabel(data, label);
537 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
538 		written = write_pos(fd, rootDirSector * 512, data, 512);
539 		if (written != 512) {
540 			dprintf("dosfs Error: write error at sector %ld\n", rootDirSector);
541 			return B_ERROR;
542 		}
543 	} else if (fatbits == 32) {
544 		int size = 512 * sectorPerCluster;
545 		uint8 *cluster = (uint8*)malloc(size);
546 		memset(cluster, 0, size);
547 		CreateVolumeLabel(cluster, label);
548 		uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize) + rootDirSectors;
549 		written = write_pos(fd, rootDirSector * 512, cluster, size);
550 		free(cluster);
551 		if (written != size) {
552 			dprintf("dosfs Error: write error at sector %ld\n", rootDirSector);
553 			return B_ERROR;
554 		}
555 	}
556 
557 	ioctl(fd, B_FLUSH_DRIVE_CACHE);
558 
559 
560 
561 	// rescan partition
562 	status = scan_partition(partitionID);
563 	if (status != B_OK)
564 		return status;
565 
566 	update_disk_device_job_progress(job, 1);
567 
568 	// print some info, if desired
569 	if (parameters.verbose) {
570 //		disk_super_block super = volume.SuperBlock();
571 
572 		dprintf("dosfs: Disk was initialized successfully.\n");
573 /*
574 		dprintf("\tname: \"%s\"\n", super.name);
575 		dprintf("\tnum blocks: %" B_PRIdOFF "\n", super.NumBlocks());
576 		dprintf("\tused blocks: %" B_PRIdOFF "\n", super.UsedBlocks());
577 		dprintf("\tblock size: %u bytes\n", (unsigned)super.BlockSize());
578 		dprintf("\tnum allocation groups: %d\n",
579 			(int)super.AllocationGroups());
580 		dprintf("\tallocation group size: %ld blocks\n",
581 			1L << super.AllocationGroupShift());
582 		dprintf("\tlog size: %u blocks\n", super.log_blocks.Length());
583 */
584 	}
585 
586 	return B_OK;
587 }
588 
589 
590 status_t
591 dosfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
592 	uint32 blockSize, disk_job_id job)
593 {
594 	if (blockSize == 0)
595 		return B_BAD_VALUE;
596 
597 	update_disk_device_job_progress(job, 0.0);
598 
599 	// just overwrite the superblock
600 	// XXX: we might want to keep the loader part ?
601 	char bootsector[512];
602 	memset(bootsector,0x00,512);
603 
604 	if (write_pos(fd, 512, bootsector, sizeof(512)) < 0)
605 		return errno;
606 
607 	update_disk_device_job_progress(job, 1.0);
608 
609 	return B_OK;
610 }
611 
612 
613 //	#pragma mark -
614 
615 
616 #if 0
617 int
618 main(int argc, char *argv[])
619 {
620 	if (sizeof(bootsector1216) != 512 || sizeof(bootsector32) != 512 || sizeof(fsinfosector32) != 512) {
621 		dprintf("compilation error: struct alignment wrong\n");
622 		return 1;
623 	}
624 
625 	const char *device = NULL;
626 	const char *label = NULL;
627 	bool noprompt = false;
628 	bool test = false;
629 	int fat = 0;
630 
631 	while (1) {
632 		int c;
633 		int option_index = 0;
634 		static struct option long_options[] =
635 		{
636 		 	{"noprompt", no_argument, 0, 'n'},
637 			{"test", no_argument, 0, 't'},
638 			{"fat", required_argument, 0, 'f'},
639 			{0, 0, 0, 0}
640 		};
641 
642 		c = getopt_long (argc, argv, "ntf:", long_options, &option_index);
643 		if (c == -1)
644 			break;
645 
646 		switch (c) {
647 			case 'n':
648 				noprompt = true;
649 		 		break;
650 
651 			case 't':
652 				test = true;
653 				break;
654 
655 			case 'f':
656 				fat = strtol(optarg, NULL, 10);
657 				if (fat == 0)
658 					fat = -1;
659 				break;
660 
661 			default:
662 		        printf("\n");
663 				PrintUsage();
664 				return 1;
665 		}
666 	}
667 
668 	if (optind < argc)
669 		device = argv[optind];
670 	if ((optind + 1) < argc)
671 		label = argv[optind + 1];
672 
673 	if (fat != 0 && fat != 12 && fat != 16 && fat != 32) {
674 		printf("mkdos error: fat must be 12, 16, or 32 bits\n");
675 		PrintUsage();
676 		return 1;
677 	}
678 
679 	if (device == NULL) {
680 		printf("mkdos error: you must specify a device or partition or image\n");
681         printf("             such as /dev/disk/ide/ata/1/master/0/0_0\n");
682 		PrintUsage();
683 		return 1;
684 	}
685 
686 	if (label == NULL) {
687 		label = "no name";
688 	}
689 
690 	if (noprompt)
691 		printf("will not prompt for confirmation\n");
692 
693 	if (test)
694 		printf("test mode enabled (no writes will occur)\n");
695 
696 	status_t s;
697 	s = Initialize(fat, device, label, noprompt, test);
698 
699 	if (s != 0) {
700 		printf("Initializing failed!\n");
701 	}
702 
703 	return (s == B_OK) ? 0 : 1;
704 }
705 #endif
706 
707 
708 void CreateVolumeLabel(void *sector, const char *label)
709 {
710 	// create a volume name directory entry in the 512 byte sector
711 	// XXX convert from UTF8, and check for valid characters
712 	// XXX this could be changed to use long file name entrys,
713 	// XXX but the dosfs would have to be updated, too
714 
715 	dirent *d = (dirent *)sector;
716 	memset(d, 0, sizeof(*d));
717 	memset(d->Name, 0x20, 11);
718 	memcpy(d->Name, label, min_c(11, strlen(label)));
719 	d->Attr = 0x08;
720 }
721