Hint added.
[AROS.git] / workbench / c / Partition / main.c
blob3268dbec5f0a5b8ea85c67911b960a16e58745c1
1 /*
2 Copyright © 2003-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /******************************************************************************
8 NAME
10 Partition
12 SYNOPSIS
14 DEVICE, UNIT/N, SYSSIZE/K/N, SYSTYPE/K, SYSNAME/K, WORKSIZE/K/N,
15 MAXWORK/S, WORKTYPE/K, WORKNAME/K, WIPE/S, FORCE/S, QUIET/S, RDB/S
17 LOCATION
21 FUNCTION
23 Partition creates either one or two AROS partitions on a given drive.
24 Existing partitions will be kept unless the WIPE option is specified
25 (or a serious bug occurs, for which we take no responsibility).
26 Partitions created by this command must be formatted before they can
27 be used.
29 By default, a single SFS System partition is created using the
30 largest amount of free space possible. A smaller size can be chosen
31 using the SYSSIZE argument. To also create a Work partition, either
32 WORKSIZE or MAXWORK must additionally be specified. The WORKSIZE
33 argument allows the size of the Work partition to be specified,
34 while setting the MAXWORK switch makes the Work partition as large
35 as possible.
37 The filesystems used by the System and Work partitions may be
38 specified using the SYSTYPE and WORKTYPE arguments respectively.
39 The available options are "SFS" (Smart Filesystem, the default), and
40 "FFSIntl" (the traditional so-called Fast Filesystem).
42 The DOS device names used for the System and Work partitions may be
43 specified using the SYSNAME and WORKNAME arguments respectively.
44 By default, these are DH0 and DH1.
46 If you wish to use only AROS on the drive you run this command on,
47 you can specify the WIPE option, which destroys all existing
48 partitions on the drive. Be very careful with this option: it
49 deletes all other operating systems and data on the drive, and could
50 be disastrous if the wrong drive is accidentally partitioned.
52 If the drive does not already contain an extended partition, one is
53 created using the largest available region of free space. The AROS
54 partitions are then created as a logical partition within. This is
55 in order to make the addition of further partitions easier.
57 INPUTS
59 DEVICE -- Device driver name (ata.device by default)
60 UNIT -- The drive's unit number (0 by default, which is the primary
61 master when using ata.device)
62 SYSSIZE -- The System (boot) partition size in megabytes.
63 SYSTYPE -- The file system to use for the system partition, either
64 "SFS" (the default) or "FFSIntl".
65 SYSNAME -- The name to use for the system partition (defaults to DH0).
66 WORKSIZE -- The Work (secondary) partition size in megabytes. To use
67 this option, SYSSIZE must also be specified.
68 MAXWORK -- Make the Work partition as large as possible. To use this
69 option, SYSSIZE must also be specified.
70 WORKTYPE -- The file system to use for the work partition, either
71 "SFS" (the default) or "FFSIntl".
72 WORKNAME -- The name to use for the work partition (defaults to DH1).
73 WIPE -- Destroy all other partitions on the drive, including those
74 used by other operating systems (CAUTION!).
75 FORCE -- Do not ask for confirmation before partitioning the drive.
76 QUIET -- Do not print any output. This option can only be used when
77 FORCE is also specified.
78 RDB -- Create only RDB partitions, no MBR or EBR partitions will be
79 created.
81 RESULT
83 Standard DOS error codes.
85 NOTES
87 Using HDToolBox instead of this command may sometimes be safer, as
88 it shows where partitions will be created on the drive before
89 changes are written to disk. However, HDToolBox can be unreliable.
91 EXAMPLE
93 Partition ata.device 1 SYSSIZE 200 MAXWORK
95 BUGS
97 SEE ALSO
99 Sys:System/Format, SFSFormat
101 ******************************************************************************/
103 #include <utility/tagitem.h>
104 #include <libraries/partition.h>
105 #include <devices/trackdisk.h>
106 #include <proto/exec.h>
107 #include <proto/dos.h>
108 #include <proto/partition.h>
109 #include <proto/utility.h>
111 #define DEBUG 0
112 #include <aros/debug.h>
114 #include "args.h"
116 #define MB (1024LL * 1024LL)
117 #define MIN_SIZE 50 /* Minimum disk space allowed in MBs */
118 #define MAX_FFS_SIZE (4L * 1024)
119 #define MAX_SFS_SIZE (124L * 1024)
120 #define MAX_SIZE(A) (((A) == &sfs0) ? MAX_SFS_SIZE : MAX_FFS_SIZE)
122 const TEXT version_string[] = "$VER: Partition 41.7 (17.10.2013)";
124 static const struct PartitionType dos3 = { "DOS\3", 4 };
125 #if AROS_BIG_ENDIAN
126 static const struct PartitionType sfs0 = { "SFS\0", 4 };
127 #else
128 /* atm, SFS is BE on AROS */
129 static const struct PartitionType sfs0 = { "SFS\0", 4 };
130 #endif
133 /*** Prototypes *************************************************************/
134 static VOID FindLargestGap(struct PartitionHandle *root, QUAD *gapLowBlock,
135 QUAD *gapHighBlock);
136 static VOID CheckGap(struct PartitionHandle *root, QUAD partLimitBlock,
137 QUAD *gapLowBlock, QUAD *gapHighBlock);
138 static struct PartitionHandle *CreateMBRPartition(
139 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl, UBYTE id);
140 static struct PartitionHandle *CreateRDBPartition(
141 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl,
142 CONST_STRPTR name, BOOL bootable, const struct PartitionType *type);
143 static ULONG MBsToCylinders(ULONG size, struct DosEnvec *de);
144 static LONG RecurviseDestroyPartitions(struct PartitionHandle *root);
146 /*** Functions **************************************************************/
147 int main(void)
149 struct PartitionHandle *diskPart = NULL, *sysPart, *workPart,
150 *root = NULL, *partition, *extPartition = NULL, *parent = NULL;
151 TEXT choice = 'N';
152 CONST_STRPTR device;
153 const struct PartitionType *sysType = NULL, *workType = NULL;
154 LONG error = 0, sysSize = 0, workSize = 0, sysHighCyl, lowCyl, highCyl,
155 reqHighCyl, unit, hasActive = FALSE;
156 QUAD rootLowBlock = 1, rootHighBlock = 0, extLowBlock = 1,
157 extHighBlock = 0, lowBlock, highBlock, rootBlocks, extBlocks;
158 UWORD partCount = 0;
160 /* Read and check arguments */
161 if (!ReadArguments())
162 error = IoErr();
164 if (error == 0)
166 if (ARG(WORKSIZE) != (IPTR)NULL && ARG(SYSSIZE) == (IPTR)NULL)
168 PutStr("ERROR: Cannot specify WORKSIZE without SYSSIZE.\n");
169 error = ERROR_REQUIRED_ARG_MISSING;
172 if (ARG(WORKSIZE) != (IPTR)NULL && ARG(MAXWORK))
174 PutStr("ERROR: Cannot specify both WORKSIZE and MAXWORK.\n");
175 error = ERROR_TOO_MANY_ARGS;
178 if (ARG(QUIET) && !ARG(FORCE))
180 PutStr("ERROR: Cannot specify QUIET without FORCE.\n");
181 error = ERROR_REQUIRED_ARG_MISSING;
184 if (ARG(SYSTYPE) != (IPTR)NULL &&
185 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "FFSIntl") != 0 &&
186 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "SFS") != 0)
188 PutStr("ERROR: SYSTYPE must be either 'FFSIntl' or 'SFS'.\n");
189 error = ERROR_REQUIRED_ARG_MISSING;
192 if (ARG(WORKTYPE) != (IPTR)NULL &&
193 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "FFSIntl") != 0 &&
194 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "SFS") != 0)
196 PutStr("ERROR: WORKTYPE must be either 'FFSIntl' or 'SFS'.\n");
197 error = ERROR_REQUIRED_ARG_MISSING;
201 if (error == 0)
203 /* Get DOSType for each partition */
204 if (ARG(SYSTYPE) == (IPTR)NULL ||
205 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "SFS") != 0)
206 sysType = &dos3;
207 else
208 sysType = &sfs0;
210 if (ARG(WORKTYPE) == (IPTR)NULL ||
211 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "FFSIntl") != 0)
212 workType = &sfs0;
213 else
214 workType = &dos3;
216 device = (CONST_STRPTR) ARG(DEVICE);
217 unit = *(LONG *)ARG(UNIT);
218 if (ARG(SYSSIZE) != (IPTR)NULL)
219 sysSize = *(LONG *)ARG(SYSSIZE);
220 if (ARG(WORKSIZE) != (IPTR)NULL)
221 workSize = *(LONG *)ARG(WORKSIZE);
223 D(bug("[C:Partition] Using %s, unit %ld\n", device, unit));
225 if (!ARG(FORCE))
227 Printf("About to partition %s unit %d.\n", device, unit);
228 if (ARG(WIPE))
229 Printf("This will DESTROY ALL DATA on the drive!\n");
230 Printf("Are you sure? (y/N)"); Flush(Output());
232 Read(Input(), &choice, 1);
234 else
236 choice = 'y';
239 if (choice != 'y' && choice != 'Y') return RETURN_WARN;
241 if (!ARG(QUIET))
243 Printf("Partitioning drive...");
244 Flush(Output());
247 D(bug("[C:Partition] Partitioning drive...\n"));
250 if (error == 0)
252 D(bug("[C:Partition] Open root partition\n"));
253 if ((root = OpenRootPartition(device, unit)) == NULL)
255 error = ERROR_UNKNOWN;
256 Printf("*** Could not open root partition of device %s, unit %d!\n", device, unit);
257 PutStr("Make sure that you provided correct device name and unit number.\n");
258 PutStr("For example primary master IDE device will most likely map to\n");
259 PutStr("ata.device, unit 0 and secondary slave to ata.device, unit 3\n");
263 /* Destroy any existing partition table if requested */
264 if (error == 0 && ARG(WIPE))
266 if (OpenPartitionTable(root) == 0)
268 D(bug("[C:Partition] WIPE partitions\n"));
269 error = RecurviseDestroyPartitions(root);
273 if (error == 0)
275 /* Open the existing partition table, or create it if none exists */
276 D(bug("[C:Partition] Opening existing root partition table..."));
277 if (OpenPartitionTable(root) != 0)
279 D(bug("failed\n[C:Partition] Creating %s root partition table\n",
280 ARG(RDB) ? "RDB" : "MBR"));
282 ULONG type = ARG(RDB) ? PHPTT_RDB : PHPTT_MBR;
283 /* Create a root partition table */
284 if (CreatePartitionTable(root, type) != 0)
286 error = ERROR_UNKNOWN;
287 PutStr("*** ERROR: Creating root partition table failed.\n");
288 CloseRootPartition(root);
289 root = NULL;
292 else
293 D(bug("ok\n"));
296 if (error == 0)
298 /* Find largest gap in root partition */
299 FindLargestGap(root, &rootLowBlock, &rootHighBlock);
301 if (!ARG(RDB))
303 /* Look for extended partition and count partitions */
304 ForeachNode(&root->table->list, partition)
306 if (OpenPartitionTable(partition) == 0)
308 if (partition->table->type == PHPTT_EBR)
309 extPartition = partition;
310 else
311 ClosePartitionTable(partition);
314 if (!hasActive)
315 GetPartitionAttrsTags(partition,
316 PT_ACTIVE, (IPTR) &hasActive, TAG_DONE);
318 partCount++;
321 /* Create extended partition if it doesn't exist */
322 if (extPartition == NULL)
324 D(bug("[C:Partition] Creating EBR partition\n"));
325 lowCyl = (rootLowBlock - 1)
326 / (LONG)(root->de.de_Surfaces * root->de.de_BlocksPerTrack)
327 + 1;
328 highCyl = (rootHighBlock + 1)
329 / (root->de.de_Surfaces * root->de.de_BlocksPerTrack) - 1;
330 extPartition =
331 CreateMBRPartition(root, lowCyl, highCyl, 0x5);
332 if (extPartition != NULL)
334 if (CreatePartitionTable(extPartition, PHPTT_EBR) != 0)
336 PutStr("*** ERROR: Creating extended partition table failed.\n");
337 extPartition = NULL;
339 rootLowBlock = 1;
340 rootHighBlock = 0;
341 partCount++;
347 if (error == 0)
349 /* Find largest gap in extended partition */
350 if (extPartition != NULL)
352 FindLargestGap(extPartition, &extLowBlock, &extHighBlock);
355 /* Choose whether to create primary or logical partition */
356 rootBlocks = rootHighBlock - rootLowBlock + 1;
357 extBlocks = extHighBlock - extLowBlock + 1;
358 if (extBlocks > rootBlocks || partCount == 4)
360 parent = extPartition;
361 lowBlock = extLowBlock;
362 highBlock = extHighBlock;
364 else
366 parent = root;
367 lowBlock = rootLowBlock;
368 highBlock = rootHighBlock;
371 /* Convert block range to cylinders */
372 lowCyl = (lowBlock - 1)
373 / (LONG)(parent->de.de_Surfaces * parent->de.de_BlocksPerTrack) + 1;
374 highCyl = (highBlock + 1)
375 / (LONG)(parent->de.de_Surfaces * parent->de.de_BlocksPerTrack) - 1;
377 /* Ensure neither partition is too large for its filesystem */
378 if ((sysSize == 0 &&
379 highCyl - lowCyl + 1 >
380 MBsToCylinders(MAX_SIZE(sysType), &parent->de)) ||
381 sysSize > MAX_SIZE(sysType))
382 sysSize = MAX_SIZE(sysType);
383 if ((ARG(MAXWORK) &&
384 (highCyl - lowCyl + 1)
385 - MBsToCylinders(sysSize, &parent->de) + 1 >
386 MBsToCylinders(MAX_SIZE(workType), &parent->de)) ||
387 workSize > MAX_SIZE(workType))
388 workSize = MAX_SIZE(workType);
390 /* Decide geometry for RDB virtual disk */
391 reqHighCyl = lowCyl + MBsToCylinders(sysSize, &parent->de)
392 + MBsToCylinders(workSize, &parent->de);
393 if (sysSize != 0 && (workSize != 0 || !ARG(MAXWORK))
394 && reqHighCyl < highCyl)
395 highCyl = reqHighCyl;
396 if (reqHighCyl > highCyl
397 || (highCyl - lowCyl + 1 < MBsToCylinders(MIN_SIZE, &parent->de)
398 && workSize == 0))
399 error = ERROR_DISK_FULL;
402 if (error == 0 && !ARG(RDB))
404 /* Create RDB virtual disk */
405 D(bug("[C:Partition] Creating RDB virtual disk\n"));
406 diskPart = CreateMBRPartition(parent, lowCyl, highCyl, 0x30);
407 if (diskPart == NULL)
409 PutStr("*** ERROR: Not enough disk space.\n");
410 error = ERROR_UNKNOWN;
414 if (error == 0 && !ARG(RDB))
416 /* Create RDB partition table inside virtual-disk partition */
417 D(bug("[C:Partition] Creating RDB partition table\n"));
418 error = CreatePartitionTable(diskPart, PHPTT_RDB);
419 if (error != 0)
421 PutStr(
422 "*** ERROR: Creating RDB partition table failed. Aborting.\n");
426 if (error == 0)
428 if (ARG(RDB))
430 diskPart = parent;
432 /* Create partitions in the RDB table */
433 sysHighCyl = sysSize != 0
434 ? lowCyl + MBsToCylinders(sysSize, &diskPart->de)
435 : highCyl;
437 /* Create System partition (defaults to FFSIntl) */
438 sysPart = CreateRDBPartition(diskPart, lowCyl, sysHighCyl, (APTR)ARG(SYSNAME),
439 TRUE, sysType);
440 if (sysPart == NULL)
441 error = ERROR_UNKNOWN;
443 if (error == 0
444 && workSize != 0
445 && sysHighCyl < diskPart->de.de_HighCyl - diskPart->de.de_LowCyl)
447 /* Create Work partition (defaults to SFS) */
448 workPart = CreateRDBPartition(diskPart, sysHighCyl + 1, highCyl,
449 (APTR)ARG(WORKNAME), FALSE, workType);
450 if (workPart == NULL)
451 error = ERROR_UNKNOWN;
454 else
456 /* Create partitions in the RDB table */
457 sysHighCyl = MBsToCylinders(sysSize, &diskPart->de);
459 /* Create System partition (defaults to FFSIntl) */
460 sysPart = CreateRDBPartition(diskPart, 0, sysHighCyl, (APTR)ARG(SYSNAME),
461 TRUE, sysType);
462 if (sysPart == NULL)
463 error = ERROR_UNKNOWN;
465 if (sysSize != 0
466 && sysHighCyl < diskPart->de.de_HighCyl - diskPart->de.de_LowCyl)
468 /* Create Work partition (defaults to SFS) */
469 workPart = CreateRDBPartition(diskPart, sysHighCyl + 1, 0,
470 (APTR)ARG(WORKNAME), FALSE, workType);
471 if (workPart == NULL)
472 error = ERROR_UNKNOWN;
477 if (error == 0)
479 /* If MBR has no active partition, make extended partition active to
480 prevent broken BIOSes from treating disk as unbootable */
481 if (!hasActive && !ARG(RDB))
482 SetPartitionAttrsTags(extPartition, PT_ACTIVE, TRUE, TAG_DONE);
484 /* Save to disk and deallocate */
485 WritePartitionTable(diskPart);
486 ClosePartitionTable(diskPart);
488 if (parent == extPartition)
490 WritePartitionTable(extPartition);
491 ClosePartitionTable(extPartition);
494 /* Save to disk and deallocate */
495 WritePartitionTable(root);
496 ClosePartitionTable(root);
499 if (root != NULL)
500 CloseRootPartition(root);
502 if (!ARG(QUIET) && error == 0) Printf("Partitioning completed\n");
504 PrintFault(error, NULL);
505 return (error == 0) ? RETURN_OK : RETURN_FAIL;
508 /* Find the low and high cylinder values for the largest gap on the disk */
509 static VOID FindLargestGap(struct PartitionHandle *root, QUAD *gapLowBlock,
510 QUAD *gapHighBlock)
512 struct PartitionHandle *partition;
513 LONG reservedBlocks = 0;
514 QUAD partLimitBlock;
516 /* Check gap between start of disk and first partition, or until end of
517 disk if there are no partitions */
518 GetPartitionTableAttrsTags(root, PTT_RESERVED, (IPTR) &reservedBlocks,
519 TAG_DONE);
520 partLimitBlock = reservedBlocks;
521 CheckGap(root, partLimitBlock, gapLowBlock, gapHighBlock);
523 /* Check gap between each partition and the next one (or end of disk for
524 the last partition)*/
525 ForeachNode(&root->table->list, partition)
527 partLimitBlock = (partition->de.de_HighCyl + 1)
528 * partition->de.de_Surfaces
529 * partition->de.de_BlocksPerTrack;
530 CheckGap(root, partLimitBlock, gapLowBlock, gapHighBlock);
533 return;
536 /* Check if the gap between the end of the current partition and the start of
537 the next one is bigger than the biggest gap previously found. If so, it is
538 stored as the new biggest gap. */
539 static VOID CheckGap(struct PartitionHandle *root, QUAD partLimitBlock,
540 QUAD *gapLowBlock, QUAD *gapHighBlock)
542 struct PartitionHandle *nextPartition;
543 QUAD lowBlock, nextLowBlock;
545 /* Search partitions for next partition by disk position */
546 nextLowBlock = (root->de.de_HighCyl - root->de.de_LowCyl + 1)
547 * root->de.de_Surfaces * root->de.de_BlocksPerTrack; /* End of disk */
548 ForeachNode(&root->table->list, nextPartition)
550 lowBlock = nextPartition->de.de_LowCyl
551 * nextPartition->de.de_Surfaces
552 * nextPartition->de.de_BlocksPerTrack;
553 if (lowBlock >= partLimitBlock && lowBlock < nextLowBlock)
555 nextLowBlock = lowBlock;
559 /* Check if the gap between the current pair of partitions is the
560 biggest gap so far */
561 if (nextLowBlock - partLimitBlock > *gapHighBlock - *gapLowBlock + 1)
563 *gapLowBlock = partLimitBlock;
564 *gapHighBlock = nextLowBlock - 1;
567 return;
570 static struct PartitionHandle *CreateMBRPartition
572 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl, UBYTE id
575 struct DriveGeometry parentDG = {0};
576 struct DosEnvec parentDE = {0},
577 partitionDE = {0};
578 struct PartitionType type = {{id}, 1};
579 struct PartitionHandle *partition;
580 IPTR reserved, leadIn = 0;
581 ULONG maxcyl;
583 GetPartitionAttrsTags
585 parent,
587 PT_DOSENVEC, (IPTR) &parentDE,
588 PT_GEOMETRY, (IPTR) &parentDG,
590 TAG_DONE
593 GetPartitionTableAttrsTags
595 parent,
596 PTT_RESERVED, (IPTR) &reserved,
597 PTT_MAXLEADIN, (IPTR) &leadIn,
598 TAG_DONE
601 if (lowcyl == 0)
603 lowcyl = (reserved - 1) /
604 (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
607 if (leadIn != 0)
609 lowcyl += (leadIn - 1) /
610 (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
613 maxcyl = parentDE.de_HighCyl - parentDE.de_LowCyl;
614 if (highcyl == 0 || highcyl > maxcyl)
616 highcyl = maxcyl;
619 CopyMem(&parentDE, &partitionDE, sizeof(struct DosEnvec));
621 partitionDE.de_SizeBlock = parentDG.dg_SectorSize >> 2;
622 partitionDE.de_Reserved = 2;
623 partitionDE.de_HighCyl = highcyl;
624 partitionDE.de_LowCyl = lowcyl;
626 partition = AddPartitionTags
628 parent,
629 PT_DOSENVEC, (IPTR) &partitionDE,
630 PT_TYPE, (IPTR) &type,
631 TAG_DONE
634 return partition;
637 static struct PartitionHandle *CreateRDBPartition
639 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl,
640 CONST_STRPTR name, BOOL bootable, const struct PartitionType *type
643 struct DriveGeometry parentDG = {0};
644 struct DosEnvec parentDE = {0},
645 partitionDE = {0};
646 struct PartitionHandle *partition;
647 ULONG maxcyl;
649 GetPartitionAttrsTags
651 parent,
653 PT_DOSENVEC, (IPTR) &parentDE,
654 PT_GEOMETRY, (IPTR) &parentDG,
656 TAG_DONE
659 if (lowcyl == 0)
661 ULONG reserved;
663 GetPartitionTableAttrsTags
665 parent, PTT_RESERVED, (IPTR) &reserved, TAG_DONE
668 lowcyl = (reserved - 1)
669 / (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
672 maxcyl = parentDE.de_HighCyl - parentDE.de_LowCyl;
673 if (highcyl == 0 || highcyl > maxcyl)
675 highcyl = maxcyl;
678 CopyMem(&parentDE, &partitionDE, sizeof(struct DosEnvec));
680 partitionDE.de_SizeBlock = parentDG.dg_SectorSize >> 2;
681 partitionDE.de_Surfaces = parentDG.dg_Heads;
682 partitionDE.de_BlocksPerTrack = parentDG.dg_TrackSectors;
683 partitionDE.de_BufMemType = parentDG.dg_BufMemType;
684 partitionDE.de_TableSize = DE_DOSTYPE;
685 partitionDE.de_Reserved = 2;
686 partitionDE.de_HighCyl = highcyl;
687 partitionDE.de_LowCyl = lowcyl;
688 partitionDE.de_NumBuffers = 100;
689 partitionDE.de_MaxTransfer = 0xFFFFFF;
690 partitionDE.de_Mask = 0xFFFFFFFE;
692 D(bug("[C:Partition] SizeBlock %ld\n", partitionDE.de_SizeBlock ));
693 D(bug("[C:Partition] Surfaces %ld\n", partitionDE.de_Surfaces));
694 D(bug("[C:Partition] BlocksPerTrack %ld\n", partitionDE.de_BlocksPerTrack));
695 D(bug("[C:Partition] BufMemType %ld\n", partitionDE.de_BufMemType));
696 D(bug("[C:Partition] TableSize %ld\n", partitionDE.de_TableSize));
697 D(bug("[C:Partition] Reserved %ld\n", partitionDE.de_Reserved));
698 D(bug("[C:Partition] HighCyl %ld\n", partitionDE.de_HighCyl));
699 D(bug("[C:Partition] LowCyl %ld\n", partitionDE.de_LowCyl));
701 partition = AddPartitionTags
703 parent,
705 PT_DOSENVEC, (IPTR) &partitionDE,
706 PT_TYPE, (IPTR) type,
707 PT_NAME, (IPTR) name,
708 PT_BOOTABLE, bootable,
709 PT_AUTOMOUNT, TRUE,
711 TAG_DONE
714 return partition;
717 /* Convert a size in megabytes into a cylinder count. The figure returned
718 is rounded down to avoid breaching maximum filesystem sizes. */
719 static ULONG MBsToCylinders(ULONG size, struct DosEnvec *de)
721 UQUAD bytes;
722 ULONG cyls = 0;
724 if (size != 0)
726 bytes = size * MB;
727 cyls = bytes / (UQUAD)(de->de_SizeBlock * sizeof(ULONG))
728 / de->de_BlocksPerTrack / de->de_Surfaces;
730 return cyls;
733 #define ZEROBUFFSIZE 4096
735 /* Go through whole partition tree and WIPE each and every entry */
736 static LONG RecurviseDestroyPartitions(struct PartitionHandle *root)
738 LONG error = 0;
740 if (root->table)
742 struct PartitionHandle *partition;
743 ForeachNode(&root->table->list, partition)
745 if (OpenPartitionTable(partition) == 0)
747 error += RecurviseDestroyPartitions(partition);
749 else
751 APTR buffer = AllocMem(ZEROBUFFSIZE, MEMF_CLEAR);
752 /* Damage first blocks of partition */
753 WritePartitionDataQ(partition, buffer, ZEROBUFFSIZE, 0);
754 FreeMem(buffer, ZEROBUFFSIZE);
759 error += DestroyPartitionTable(root);
761 return error;