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
18void PrintUsage();
19status_t Initialize(int fatbits, const char *device, const char *label,
20	bool noprompt, bool testmode);
21status_t parse_initialize_parameters(const char* parameterString,
22	initialize_parameters& parameters);
23
24
25static void
26create_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
41status_t
42check_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
55status_t
56parse_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
91status_t
92dosfs_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
632status_t
633dosfs_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
659int
660main(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