Prevent partitions from extending beyond end of container partition.
[AROS.git] / workbench / c / Partition / main.c
blob5bb5a6587ea86fa1f8f31965e91449707f6d3a10
1 /*
2 Copyright © 2003-2011, 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.4 (16.6.2011)";
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);
145 /*** Functions **************************************************************/
146 int main(void)
148 struct PartitionHandle *diskPart = NULL, *sysPart, *workPart,
149 *root = NULL, *partition, *extPartition = NULL, *parent = NULL;
150 TEXT choice = 'N';
151 CONST_STRPTR device;
152 const struct PartitionType *sysType = NULL, *workType = NULL;
153 LONG error = 0, sysSize = 0, workSize = 0, sysHighCyl, lowCyl, highCyl,
154 reqHighCyl, unit, hasActive = FALSE;
155 QUAD rootLowBlock = 1, rootHighBlock = 0, extLowBlock = 1,
156 extHighBlock = 0, lowBlock, highBlock, rootBlocks, extBlocks;
157 UWORD partCount = 0;
159 /* Read and check arguments */
160 if (!ReadArguments())
161 error = IoErr();
163 if (error == 0)
165 if (ARG(WORKSIZE) != (IPTR)NULL && ARG(SYSSIZE) == (IPTR)NULL)
167 PutStr("ERROR: Cannot specify WORKSIZE without SYSSIZE.\n");
168 error = ERROR_REQUIRED_ARG_MISSING;
171 if (ARG(WORKSIZE) != (IPTR)NULL && ARG(MAXWORK))
173 PutStr("ERROR: Cannot specify both WORKSIZE and MAXWORK.\n");
174 error = ERROR_TOO_MANY_ARGS;
177 if (ARG(QUIET) && !ARG(FORCE))
179 PutStr("ERROR: Cannot specify QUIET without FORCE.\n");
180 error = ERROR_REQUIRED_ARG_MISSING;
183 if (ARG(SYSTYPE) != (IPTR)NULL &&
184 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "FFSIntl") != 0 &&
185 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "SFS") != 0)
187 PutStr("ERROR: SYSTYPE must be either 'FFSIntl' or 'SFS'.\n");
188 error = ERROR_REQUIRED_ARG_MISSING;
191 if (ARG(WORKTYPE) != (IPTR)NULL &&
192 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "FFSIntl") != 0 &&
193 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "SFS") != 0)
195 PutStr("ERROR: WORKTYPE must be either 'FFSIntl' or 'SFS'.\n");
196 error = ERROR_REQUIRED_ARG_MISSING;
200 if (error == 0)
202 /* Get DOSType for each partition */
203 if (ARG(SYSTYPE) == (IPTR)NULL ||
204 Stricmp((CONST_STRPTR)ARG(SYSTYPE), "SFS") != 0)
205 sysType = &dos3;
206 else
207 sysType = &sfs0;
209 if (ARG(WORKTYPE) == (IPTR)NULL ||
210 Stricmp((CONST_STRPTR)ARG(WORKTYPE), "FFSIntl") != 0)
211 workType = &sfs0;
212 else
213 workType = &dos3;
215 device = (CONST_STRPTR) ARG(DEVICE);
216 unit = *(LONG *)ARG(UNIT);
217 if (ARG(SYSSIZE) != (IPTR)NULL)
218 sysSize = *(LONG *)ARG(SYSSIZE);
219 if (ARG(WORKSIZE) != (IPTR)NULL)
220 workSize = *(LONG *)ARG(WORKSIZE);
222 D(bug("[C:Partition] Using %s, unit %ld\n", device, unit));
224 if (!ARG(FORCE))
226 Printf("About to partition %s unit %d.\n", device, unit);
227 if (ARG(WIPE))
228 Printf("This will DESTROY ALL DATA on the drive!\n");
229 Printf("Are you sure? (y/N)"); Flush(Output());
231 Read(Input(), &choice, 1);
233 else
235 choice = 'y';
238 if (choice != 'y' && choice != 'Y') return RETURN_WARN;
240 if (!ARG(QUIET))
242 Printf("Partitioning drive...");
243 Flush(Output());
246 D(bug("[C:Partition] Partitioning drive...\n"));
249 if (error == 0)
251 D(bug("[C:Partition] Open root partition\n"));
252 if ((root = OpenRootPartition(device, unit)) == NULL)
254 error = ERROR_UNKNOWN;
255 PutStr("*** Could not open root partition!\n");
259 /* Destroy any existing partition table if requested */
260 if (error == 0 && ARG(WIPE))
262 if (OpenPartitionTable(root) == 0)
264 D(bug("[C:Partition] WIPE root partition table\n"));
265 error = DestroyPartitionTable(root);
269 if (error == 0)
271 /* Open the existing partition table, or create it if none exists */
272 D(bug("[C:Partition] Opening existing root partition table..."));
273 if (OpenPartitionTable(root) != 0)
275 D(bug("failed\n[C:Partition] Creating %s root partition table\n",
276 ARG(RDB) ? "RDB" : "MBR"));
278 ULONG type = ARG(RDB) ? PHPTT_RDB : PHPTT_MBR;
279 /* Create a root partition table */
280 if (CreatePartitionTable(root, type) != 0)
282 error = ERROR_UNKNOWN;
283 PutStr("*** ERROR: Creating root partition table failed.\n");
284 CloseRootPartition(root);
285 root = NULL;
288 else
289 D(bug("ok\n"));
292 if (error == 0)
294 /* Find largest gap in root partition */
295 FindLargestGap(root, &rootLowBlock, &rootHighBlock);
297 if (!ARG(RDB))
299 /* Look for extended partition and count partitions */
300 ForeachNode(&root->table->list, partition)
302 if (OpenPartitionTable(partition) == 0)
304 if (partition->table->type == PHPTT_EBR)
305 extPartition = partition;
306 else
307 ClosePartitionTable(partition);
310 if (!hasActive)
311 GetPartitionAttrsTags(partition,
312 PT_ACTIVE, (IPTR) &hasActive, TAG_DONE);
314 partCount++;
317 /* Create extended partition if it doesn't exist */
318 if (extPartition == NULL)
320 D(bug("[C:Partition] Creating EBR partition\n"));
321 lowCyl = (rootLowBlock - 1)
322 / (LONG)(root->de.de_Surfaces * root->de.de_BlocksPerTrack)
323 + 1;
324 highCyl = (rootHighBlock + 1)
325 / (root->de.de_Surfaces * root->de.de_BlocksPerTrack) - 1;
326 extPartition =
327 CreateMBRPartition(root, lowCyl, highCyl, 0x5);
328 if (extPartition != NULL)
330 if (CreatePartitionTable(extPartition, PHPTT_EBR) != 0)
332 PutStr("*** ERROR: Creating extended partition table failed.\n");
333 extPartition = NULL;
335 rootLowBlock = 1;
336 rootHighBlock = 0;
337 partCount++;
343 if (error == 0)
345 /* Find largest gap in extended partition */
346 if (extPartition != NULL)
348 FindLargestGap(extPartition, &extLowBlock, &extHighBlock);
351 /* Choose whether to create primary or logical partition */
352 rootBlocks = rootHighBlock - rootLowBlock + 1;
353 extBlocks = extHighBlock - extLowBlock + 1;
354 if (extBlocks > rootBlocks || partCount == 4)
356 parent = extPartition;
357 lowBlock = extLowBlock;
358 highBlock = extHighBlock;
360 else
362 parent = root;
363 lowBlock = rootLowBlock;
364 highBlock = rootHighBlock;
367 /* Convert block range to cylinders */
368 lowCyl = ((LONG)lowBlock - 1)
369 / (LONG)(parent->de.de_Surfaces * parent->de.de_BlocksPerTrack) + 1;
370 highCyl = ((LONG)highBlock + 1)
371 / (LONG)(parent->de.de_Surfaces * parent->de.de_BlocksPerTrack) - 1;
373 /* Ensure neither partition is too large for its filesystem */
374 if ((sysSize == 0 &&
375 highCyl - lowCyl + 1 >
376 MBsToCylinders(MAX_SIZE(sysType), &parent->de)) ||
377 sysSize > MAX_SIZE(sysType))
378 sysSize = MAX_SIZE(sysType);
379 if ((ARG(MAXWORK) &&
380 (highCyl - lowCyl + 1)
381 - MBsToCylinders(sysSize, &parent->de) + 1 >
382 MBsToCylinders(MAX_SIZE(workType), &parent->de)) ||
383 workSize > MAX_SIZE(workType))
384 workSize = MAX_SIZE(workType);
386 /* Decide geometry for RDB virtual disk */
387 reqHighCyl = lowCyl + MBsToCylinders(sysSize, &parent->de)
388 + MBsToCylinders(workSize, &parent->de);
389 if (sysSize != 0 && (workSize != 0 || !ARG(MAXWORK))
390 && reqHighCyl < highCyl)
391 highCyl = reqHighCyl;
392 if (reqHighCyl > highCyl
393 || (highCyl - lowCyl + 1 < MBsToCylinders(MIN_SIZE, &parent->de)
394 && workSize == 0))
395 error = ERROR_DISK_FULL;
398 if (error == 0 && !ARG(RDB))
400 /* Create RDB virtual disk */
401 D(bug("[C:Partition] Creating RDB virtual disk\n"));
402 diskPart = CreateMBRPartition(parent, lowCyl, highCyl, 0x30);
403 if (diskPart == NULL)
405 PutStr("*** ERROR: Not enough disk space.\n");
406 error = ERROR_UNKNOWN;
410 if (error == 0 && !ARG(RDB))
412 /* Create RDB partition table inside virtual-disk partition */
413 D(bug("[C:Partition] Creating RDB partition table\n"));
414 error = CreatePartitionTable(diskPart, PHPTT_RDB);
415 if (error != 0)
417 PutStr(
418 "*** ERROR: Creating RDB partition table failed. Aborting.\n");
422 if (error == 0)
424 if (ARG(RDB))
426 diskPart = parent;
428 /* Create partitions in the RDB table */
429 sysHighCyl = sysSize != 0
430 ? lowCyl + MBsToCylinders(sysSize, &diskPart->de)
431 : highCyl;
433 /* Create System partition (defaults to FFSIntl) */
434 sysPart = CreateRDBPartition(diskPart, lowCyl, sysHighCyl, (APTR)ARG(SYSNAME),
435 TRUE, sysType);
436 if (sysPart == NULL)
437 error = ERROR_UNKNOWN;
439 if (error == 0
440 && workSize != 0
441 && sysHighCyl < diskPart->de.de_HighCyl - diskPart->de.de_LowCyl)
443 /* Create Work partition (defaults to SFS) */
444 workPart = CreateRDBPartition(diskPart, sysHighCyl + 1, highCyl,
445 (APTR)ARG(WORKNAME), FALSE, workType);
446 if (workPart == NULL)
447 error = ERROR_UNKNOWN;
450 else
452 /* Create partitions in the RDB table */
453 sysHighCyl = MBsToCylinders(sysSize, &diskPart->de);
455 /* Create System partition (defaults to FFSIntl) */
456 sysPart = CreateRDBPartition(diskPart, 0, sysHighCyl, (APTR)ARG(SYSNAME),
457 TRUE, sysType);
458 if (sysPart == NULL)
459 error = ERROR_UNKNOWN;
461 if (sysSize != 0
462 && sysHighCyl < diskPart->de.de_HighCyl - diskPart->de.de_LowCyl)
464 /* Create Work partition (defaults to SFS) */
465 workPart = CreateRDBPartition(diskPart, sysHighCyl + 1, 0,
466 (APTR)ARG(WORKNAME), FALSE, workType);
467 if (workPart == NULL)
468 error = ERROR_UNKNOWN;
473 if (error == 0)
475 /* If MBR has no active partition, make extended partition active to
476 prevent broken BIOSes from treating disk as unbootable */
477 if (!hasActive && !ARG(RDB))
478 SetPartitionAttrsTags(extPartition, PT_ACTIVE, TRUE, TAG_DONE);
480 /* Save to disk and deallocate */
481 WritePartitionTable(diskPart);
482 ClosePartitionTable(diskPart);
484 if (parent == extPartition)
486 WritePartitionTable(extPartition);
487 ClosePartitionTable(extPartition);
490 /* Save to disk and deallocate */
491 WritePartitionTable(root);
492 ClosePartitionTable(root);
495 if (root != NULL)
496 CloseRootPartition(root);
498 if (!ARG(QUIET) && error == 0) Printf("Partitioning completed\n");
500 PrintFault(error, NULL);
501 return (error == 0) ? RETURN_OK : RETURN_FAIL;
504 /* Find the low and high cylinder values for the largest gap on the disk */
505 static VOID FindLargestGap(struct PartitionHandle *root, QUAD *gapLowBlock,
506 QUAD *gapHighBlock)
508 struct PartitionHandle *partition;
509 LONG reservedBlocks = 0;
510 QUAD partLimitBlock;
512 /* Check gap between start of disk and first partition, or until end of
513 disk if there are no partitions */
514 GetPartitionTableAttrsTags(root, PTT_RESERVED, (IPTR) &reservedBlocks,
515 TAG_DONE);
516 partLimitBlock = reservedBlocks;
517 CheckGap(root, partLimitBlock, gapLowBlock, gapHighBlock);
519 /* Check gap between each partition and the next one (or end of disk for
520 the last partition)*/
521 ForeachNode(&root->table->list, partition)
523 partLimitBlock = (partition->de.de_HighCyl + 1)
524 * partition->de.de_Surfaces
525 * partition->de.de_BlocksPerTrack;
526 CheckGap(root, partLimitBlock, gapLowBlock, gapHighBlock);
529 return;
532 /* Check if the gap between the end of the current partition and the start of
533 the next one is bigger than the biggest gap previously found. If so, it is
534 stored as the new biggest gap. */
535 static VOID CheckGap(struct PartitionHandle *root, QUAD partLimitBlock,
536 QUAD *gapLowBlock, QUAD *gapHighBlock)
538 struct PartitionHandle *nextPartition;
539 QUAD lowBlock, nextLowBlock;
541 /* Search partitions for next partition by disk position */
542 nextLowBlock = (root->de.de_HighCyl - root->de.de_LowCyl + 1)
543 * root->de.de_Surfaces * root->de.de_BlocksPerTrack; /* End of disk */
544 ForeachNode(&root->table->list, nextPartition)
546 lowBlock = nextPartition->de.de_LowCyl
547 * nextPartition->de.de_Surfaces
548 * nextPartition->de.de_BlocksPerTrack;
549 if (lowBlock >= partLimitBlock && lowBlock < nextLowBlock)
551 nextLowBlock = lowBlock;
555 /* Check if the gap between the current pair of partitions is the
556 biggest gap so far */
557 if (nextLowBlock - partLimitBlock > *gapHighBlock - *gapLowBlock + 1)
559 *gapLowBlock = partLimitBlock;
560 *gapHighBlock = nextLowBlock - 1;
563 return;
566 static struct PartitionHandle *CreateMBRPartition
568 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl, UBYTE id
571 struct DriveGeometry parentDG = {0};
572 struct DosEnvec parentDE = {0},
573 partitionDE = {0};
574 struct PartitionType type = {{id}, 1};
575 struct PartitionHandle *partition;
576 IPTR reserved, leadIn = 0;
577 ULONG maxcyl;
579 GetPartitionAttrsTags
581 parent,
583 PT_DOSENVEC, (IPTR) &parentDE,
584 PT_GEOMETRY, (IPTR) &parentDG,
586 TAG_DONE
589 GetPartitionTableAttrsTags
591 parent,
592 PTT_RESERVED, (IPTR) &reserved,
593 PTT_MAXLEADIN, (IPTR) &leadIn,
594 TAG_DONE
597 if (lowcyl == 0)
599 lowcyl = (reserved - 1) /
600 (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
603 if (leadIn != 0)
605 lowcyl += (leadIn - 1) /
606 (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
609 maxcyl = parentDE.de_HighCyl - parentDE.de_LowCyl;
610 if (highcyl == 0 || highcyl > maxcyl)
612 highcyl = maxcyl;
615 CopyMem(&parentDE, &partitionDE, sizeof(struct DosEnvec));
617 partitionDE.de_SizeBlock = parentDG.dg_SectorSize >> 2;
618 partitionDE.de_Reserved = 2;
619 partitionDE.de_HighCyl = highcyl;
620 partitionDE.de_LowCyl = lowcyl;
622 partition = AddPartitionTags
624 parent,
625 PT_DOSENVEC, (IPTR) &partitionDE,
626 PT_TYPE, (IPTR) &type,
627 TAG_DONE
630 return partition;
633 static struct PartitionHandle *CreateRDBPartition
635 struct PartitionHandle *parent, ULONG lowcyl, ULONG highcyl,
636 CONST_STRPTR name, BOOL bootable, const struct PartitionType *type
639 struct DriveGeometry parentDG = {0};
640 struct DosEnvec parentDE = {0},
641 partitionDE = {0};
642 struct PartitionHandle *partition;
643 ULONG maxcyl;
645 GetPartitionAttrsTags
647 parent,
649 PT_DOSENVEC, (IPTR) &parentDE,
650 PT_GEOMETRY, (IPTR) &parentDG,
652 TAG_DONE
655 if (lowcyl == 0)
657 ULONG reserved;
659 GetPartitionTableAttrsTags
661 parent, PTT_RESERVED, (IPTR) &reserved, TAG_DONE
664 lowcyl = (reserved - 1)
665 / (parentDG.dg_Heads * parentDG.dg_TrackSectors) + 1;
668 maxcyl = parentDE.de_HighCyl - parentDE.de_LowCyl;
669 if (highcyl == 0 || highcyl > maxcyl)
671 highcyl = maxcyl;
674 CopyMem(&parentDE, &partitionDE, sizeof(struct DosEnvec));
676 partitionDE.de_SizeBlock = parentDG.dg_SectorSize >> 2;
677 partitionDE.de_Surfaces = parentDG.dg_Heads;
678 partitionDE.de_BlocksPerTrack = parentDG.dg_TrackSectors;
679 partitionDE.de_BufMemType = parentDG.dg_BufMemType;
680 partitionDE.de_TableSize = DE_DOSTYPE;
681 partitionDE.de_Reserved = 2;
682 partitionDE.de_HighCyl = highcyl;
683 partitionDE.de_LowCyl = lowcyl;
684 partitionDE.de_NumBuffers = 100;
685 partitionDE.de_MaxTransfer = 0xFFFFFF;
686 partitionDE.de_Mask = 0xFFFFFFFE;
688 D(bug("[C:Partition] SizeBlock %ld\n", partitionDE.de_SizeBlock ));
689 D(bug("[C:Partition] Surfaces %ld\n", partitionDE.de_Surfaces));
690 D(bug("[C:Partition] BlocksPerTrack %ld\n", partitionDE.de_BlocksPerTrack));
691 D(bug("[C:Partition] BufMemType %ld\n", partitionDE.de_BufMemType));
692 D(bug("[C:Partition] TableSize %ld\n", partitionDE.de_TableSize));
693 D(bug("[C:Partition] Reserved %ld\n", partitionDE.de_Reserved));
694 D(bug("[C:Partition] HighCyl %ld\n", partitionDE.de_HighCyl));
695 D(bug("[C:Partition] LowCyl %ld\n", partitionDE.de_LowCyl));
697 partition = AddPartitionTags
699 parent,
701 PT_DOSENVEC, (IPTR) &partitionDE,
702 PT_TYPE, (IPTR) type,
703 PT_NAME, (IPTR) name,
704 PT_BOOTABLE, bootable,
705 PT_AUTOMOUNT, TRUE,
707 TAG_DONE
710 return partition;
713 /* Convert a size in megabytes into a cylinder count. The figure returned
714 is rounded down to avoid breaching maximum filesystem sizes. */
715 static ULONG MBsToCylinders(ULONG size, struct DosEnvec *de)
717 UQUAD bytes;
718 ULONG cyls = 0;
720 if (size != 0)
722 bytes = size * MB;
723 cyls = bytes / (UQUAD)(de->de_SizeBlock * sizeof(ULONG))
724 / de->de_BlocksPerTrack / de->de_Surfaces;
726 return cyls;