2 Copyright © 2003-2013, The AROS Development Team. All rights reserved.
6 /******************************************************************************
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
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
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
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.
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
83 Standard DOS error codes.
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.
93 Partition ata.device 1 SYSSIZE 200 MAXWORK
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>
112 #include <aros/debug.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.6 (15.10.2013)";
124 static const struct PartitionType dos3
= { "DOS\3", 4 };
126 static const struct PartitionType sfs0
= { "SFS\0", 4 };
128 /* atm, SFS is BE on AROS */
129 static const struct PartitionType sfs0
= { "SFS\0", 4 };
133 /*** Prototypes *************************************************************/
134 static VOID
FindLargestGap(struct PartitionHandle
*root
, QUAD
*gapLowBlock
,
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 **************************************************************/
149 struct PartitionHandle
*diskPart
= NULL
, *sysPart
, *workPart
,
150 *root
= NULL
, *partition
, *extPartition
= NULL
, *parent
= NULL
;
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
;
160 /* Read and check arguments */
161 if (!ReadArguments())
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
;
203 /* Get DOSType for each partition */
204 if (ARG(SYSTYPE
) == (IPTR
)NULL
||
205 Stricmp((CONST_STRPTR
)ARG(SYSTYPE
), "SFS") != 0)
210 if (ARG(WORKTYPE
) == (IPTR
)NULL
||
211 Stricmp((CONST_STRPTR
)ARG(WORKTYPE
), "FFSIntl") != 0)
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
));
227 Printf("About to partition %s unit %d.\n", device
, unit
);
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);
239 if (choice
!= 'y' && choice
!= 'Y') return RETURN_WARN
;
243 Printf("Partitioning drive...");
247 D(bug("[C:Partition] Partitioning drive...\n"));
252 D(bug("[C:Partition] Open root partition\n"));
253 if ((root
= OpenRootPartition(device
, unit
)) == NULL
)
255 error
= ERROR_UNKNOWN
;
256 PutStr("*** Could not open root partition!\n");
260 /* Destroy any existing partition table if requested */
261 if (error
== 0 && ARG(WIPE
))
263 if (OpenPartitionTable(root
) == 0)
265 D(bug("[C:Partition] WIPE partitions\n"));
266 error
= RecurviseDestroyPartitions(root
);
272 /* Open the existing partition table, or create it if none exists */
273 D(bug("[C:Partition] Opening existing root partition table..."));
274 if (OpenPartitionTable(root
) != 0)
276 D(bug("failed\n[C:Partition] Creating %s root partition table\n",
277 ARG(RDB
) ? "RDB" : "MBR"));
279 ULONG type
= ARG(RDB
) ? PHPTT_RDB
: PHPTT_MBR
;
280 /* Create a root partition table */
281 if (CreatePartitionTable(root
, type
) != 0)
283 error
= ERROR_UNKNOWN
;
284 PutStr("*** ERROR: Creating root partition table failed.\n");
285 CloseRootPartition(root
);
295 /* Find largest gap in root partition */
296 FindLargestGap(root
, &rootLowBlock
, &rootHighBlock
);
300 /* Look for extended partition and count partitions */
301 ForeachNode(&root
->table
->list
, partition
)
303 if (OpenPartitionTable(partition
) == 0)
305 if (partition
->table
->type
== PHPTT_EBR
)
306 extPartition
= partition
;
308 ClosePartitionTable(partition
);
312 GetPartitionAttrsTags(partition
,
313 PT_ACTIVE
, (IPTR
) &hasActive
, TAG_DONE
);
318 /* Create extended partition if it doesn't exist */
319 if (extPartition
== NULL
)
321 D(bug("[C:Partition] Creating EBR partition\n"));
322 lowCyl
= (rootLowBlock
- 1)
323 / (LONG
)(root
->de
.de_Surfaces
* root
->de
.de_BlocksPerTrack
)
325 highCyl
= (rootHighBlock
+ 1)
326 / (root
->de
.de_Surfaces
* root
->de
.de_BlocksPerTrack
) - 1;
328 CreateMBRPartition(root
, lowCyl
, highCyl
, 0x5);
329 if (extPartition
!= NULL
)
331 if (CreatePartitionTable(extPartition
, PHPTT_EBR
) != 0)
333 PutStr("*** ERROR: Creating extended partition table failed.\n");
346 /* Find largest gap in extended partition */
347 if (extPartition
!= NULL
)
349 FindLargestGap(extPartition
, &extLowBlock
, &extHighBlock
);
352 /* Choose whether to create primary or logical partition */
353 rootBlocks
= rootHighBlock
- rootLowBlock
+ 1;
354 extBlocks
= extHighBlock
- extLowBlock
+ 1;
355 if (extBlocks
> rootBlocks
|| partCount
== 4)
357 parent
= extPartition
;
358 lowBlock
= extLowBlock
;
359 highBlock
= extHighBlock
;
364 lowBlock
= rootLowBlock
;
365 highBlock
= rootHighBlock
;
368 /* Convert block range to cylinders */
369 lowCyl
= (lowBlock
- 1)
370 / (LONG
)(parent
->de
.de_Surfaces
* parent
->de
.de_BlocksPerTrack
) + 1;
371 highCyl
= (highBlock
+ 1)
372 / (LONG
)(parent
->de
.de_Surfaces
* parent
->de
.de_BlocksPerTrack
) - 1;
374 /* Ensure neither partition is too large for its filesystem */
376 highCyl
- lowCyl
+ 1 >
377 MBsToCylinders(MAX_SIZE(sysType
), &parent
->de
)) ||
378 sysSize
> MAX_SIZE(sysType
))
379 sysSize
= MAX_SIZE(sysType
);
381 (highCyl
- lowCyl
+ 1)
382 - MBsToCylinders(sysSize
, &parent
->de
) + 1 >
383 MBsToCylinders(MAX_SIZE(workType
), &parent
->de
)) ||
384 workSize
> MAX_SIZE(workType
))
385 workSize
= MAX_SIZE(workType
);
387 /* Decide geometry for RDB virtual disk */
388 reqHighCyl
= lowCyl
+ MBsToCylinders(sysSize
, &parent
->de
)
389 + MBsToCylinders(workSize
, &parent
->de
);
390 if (sysSize
!= 0 && (workSize
!= 0 || !ARG(MAXWORK
))
391 && reqHighCyl
< highCyl
)
392 highCyl
= reqHighCyl
;
393 if (reqHighCyl
> highCyl
394 || (highCyl
- lowCyl
+ 1 < MBsToCylinders(MIN_SIZE
, &parent
->de
)
396 error
= ERROR_DISK_FULL
;
399 if (error
== 0 && !ARG(RDB
))
401 /* Create RDB virtual disk */
402 D(bug("[C:Partition] Creating RDB virtual disk\n"));
403 diskPart
= CreateMBRPartition(parent
, lowCyl
, highCyl
, 0x30);
404 if (diskPart
== NULL
)
406 PutStr("*** ERROR: Not enough disk space.\n");
407 error
= ERROR_UNKNOWN
;
411 if (error
== 0 && !ARG(RDB
))
413 /* Create RDB partition table inside virtual-disk partition */
414 D(bug("[C:Partition] Creating RDB partition table\n"));
415 error
= CreatePartitionTable(diskPart
, PHPTT_RDB
);
419 "*** ERROR: Creating RDB partition table failed. Aborting.\n");
429 /* Create partitions in the RDB table */
430 sysHighCyl
= sysSize
!= 0
431 ? lowCyl
+ MBsToCylinders(sysSize
, &diskPart
->de
)
434 /* Create System partition (defaults to FFSIntl) */
435 sysPart
= CreateRDBPartition(diskPart
, lowCyl
, sysHighCyl
, (APTR
)ARG(SYSNAME
),
438 error
= ERROR_UNKNOWN
;
442 && sysHighCyl
< diskPart
->de
.de_HighCyl
- diskPart
->de
.de_LowCyl
)
444 /* Create Work partition (defaults to SFS) */
445 workPart
= CreateRDBPartition(diskPart
, sysHighCyl
+ 1, highCyl
,
446 (APTR
)ARG(WORKNAME
), FALSE
, workType
);
447 if (workPart
== NULL
)
448 error
= ERROR_UNKNOWN
;
453 /* Create partitions in the RDB table */
454 sysHighCyl
= MBsToCylinders(sysSize
, &diskPart
->de
);
456 /* Create System partition (defaults to FFSIntl) */
457 sysPart
= CreateRDBPartition(diskPart
, 0, sysHighCyl
, (APTR
)ARG(SYSNAME
),
460 error
= ERROR_UNKNOWN
;
463 && sysHighCyl
< diskPart
->de
.de_HighCyl
- diskPart
->de
.de_LowCyl
)
465 /* Create Work partition (defaults to SFS) */
466 workPart
= CreateRDBPartition(diskPart
, sysHighCyl
+ 1, 0,
467 (APTR
)ARG(WORKNAME
), FALSE
, workType
);
468 if (workPart
== NULL
)
469 error
= ERROR_UNKNOWN
;
476 /* If MBR has no active partition, make extended partition active to
477 prevent broken BIOSes from treating disk as unbootable */
478 if (!hasActive
&& !ARG(RDB
))
479 SetPartitionAttrsTags(extPartition
, PT_ACTIVE
, TRUE
, TAG_DONE
);
481 /* Save to disk and deallocate */
482 WritePartitionTable(diskPart
);
483 ClosePartitionTable(diskPart
);
485 if (parent
== extPartition
)
487 WritePartitionTable(extPartition
);
488 ClosePartitionTable(extPartition
);
491 /* Save to disk and deallocate */
492 WritePartitionTable(root
);
493 ClosePartitionTable(root
);
497 CloseRootPartition(root
);
499 if (!ARG(QUIET
) && error
== 0) Printf("Partitioning completed\n");
501 PrintFault(error
, NULL
);
502 return (error
== 0) ? RETURN_OK
: RETURN_FAIL
;
505 /* Find the low and high cylinder values for the largest gap on the disk */
506 static VOID
FindLargestGap(struct PartitionHandle
*root
, QUAD
*gapLowBlock
,
509 struct PartitionHandle
*partition
;
510 LONG reservedBlocks
= 0;
513 /* Check gap between start of disk and first partition, or until end of
514 disk if there are no partitions */
515 GetPartitionTableAttrsTags(root
, PTT_RESERVED
, (IPTR
) &reservedBlocks
,
517 partLimitBlock
= reservedBlocks
;
518 CheckGap(root
, partLimitBlock
, gapLowBlock
, gapHighBlock
);
520 /* Check gap between each partition and the next one (or end of disk for
521 the last partition)*/
522 ForeachNode(&root
->table
->list
, partition
)
524 partLimitBlock
= (partition
->de
.de_HighCyl
+ 1)
525 * partition
->de
.de_Surfaces
526 * partition
->de
.de_BlocksPerTrack
;
527 CheckGap(root
, partLimitBlock
, gapLowBlock
, gapHighBlock
);
533 /* Check if the gap between the end of the current partition and the start of
534 the next one is bigger than the biggest gap previously found. If so, it is
535 stored as the new biggest gap. */
536 static VOID
CheckGap(struct PartitionHandle
*root
, QUAD partLimitBlock
,
537 QUAD
*gapLowBlock
, QUAD
*gapHighBlock
)
539 struct PartitionHandle
*nextPartition
;
540 QUAD lowBlock
, nextLowBlock
;
542 /* Search partitions for next partition by disk position */
543 nextLowBlock
= (root
->de
.de_HighCyl
- root
->de
.de_LowCyl
+ 1)
544 * root
->de
.de_Surfaces
* root
->de
.de_BlocksPerTrack
; /* End of disk */
545 ForeachNode(&root
->table
->list
, nextPartition
)
547 lowBlock
= nextPartition
->de
.de_LowCyl
548 * nextPartition
->de
.de_Surfaces
549 * nextPartition
->de
.de_BlocksPerTrack
;
550 if (lowBlock
>= partLimitBlock
&& lowBlock
< nextLowBlock
)
552 nextLowBlock
= lowBlock
;
556 /* Check if the gap between the current pair of partitions is the
557 biggest gap so far */
558 if (nextLowBlock
- partLimitBlock
> *gapHighBlock
- *gapLowBlock
+ 1)
560 *gapLowBlock
= partLimitBlock
;
561 *gapHighBlock
= nextLowBlock
- 1;
567 static struct PartitionHandle
*CreateMBRPartition
569 struct PartitionHandle
*parent
, ULONG lowcyl
, ULONG highcyl
, UBYTE id
572 struct DriveGeometry parentDG
= {0};
573 struct DosEnvec parentDE
= {0},
575 struct PartitionType type
= {{id
}, 1};
576 struct PartitionHandle
*partition
;
577 IPTR reserved
, leadIn
= 0;
580 GetPartitionAttrsTags
584 PT_DOSENVEC
, (IPTR
) &parentDE
,
585 PT_GEOMETRY
, (IPTR
) &parentDG
,
590 GetPartitionTableAttrsTags
593 PTT_RESERVED
, (IPTR
) &reserved
,
594 PTT_MAXLEADIN
, (IPTR
) &leadIn
,
600 lowcyl
= (reserved
- 1) /
601 (parentDG
.dg_Heads
* parentDG
.dg_TrackSectors
) + 1;
606 lowcyl
+= (leadIn
- 1) /
607 (parentDG
.dg_Heads
* parentDG
.dg_TrackSectors
) + 1;
610 maxcyl
= parentDE
.de_HighCyl
- parentDE
.de_LowCyl
;
611 if (highcyl
== 0 || highcyl
> maxcyl
)
616 CopyMem(&parentDE
, &partitionDE
, sizeof(struct DosEnvec
));
618 partitionDE
.de_SizeBlock
= parentDG
.dg_SectorSize
>> 2;
619 partitionDE
.de_Reserved
= 2;
620 partitionDE
.de_HighCyl
= highcyl
;
621 partitionDE
.de_LowCyl
= lowcyl
;
623 partition
= AddPartitionTags
626 PT_DOSENVEC
, (IPTR
) &partitionDE
,
627 PT_TYPE
, (IPTR
) &type
,
634 static struct PartitionHandle
*CreateRDBPartition
636 struct PartitionHandle
*parent
, ULONG lowcyl
, ULONG highcyl
,
637 CONST_STRPTR name
, BOOL bootable
, const struct PartitionType
*type
640 struct DriveGeometry parentDG
= {0};
641 struct DosEnvec parentDE
= {0},
643 struct PartitionHandle
*partition
;
646 GetPartitionAttrsTags
650 PT_DOSENVEC
, (IPTR
) &parentDE
,
651 PT_GEOMETRY
, (IPTR
) &parentDG
,
660 GetPartitionTableAttrsTags
662 parent
, PTT_RESERVED
, (IPTR
) &reserved
, TAG_DONE
665 lowcyl
= (reserved
- 1)
666 / (parentDG
.dg_Heads
* parentDG
.dg_TrackSectors
) + 1;
669 maxcyl
= parentDE
.de_HighCyl
- parentDE
.de_LowCyl
;
670 if (highcyl
== 0 || highcyl
> maxcyl
)
675 CopyMem(&parentDE
, &partitionDE
, sizeof(struct DosEnvec
));
677 partitionDE
.de_SizeBlock
= parentDG
.dg_SectorSize
>> 2;
678 partitionDE
.de_Surfaces
= parentDG
.dg_Heads
;
679 partitionDE
.de_BlocksPerTrack
= parentDG
.dg_TrackSectors
;
680 partitionDE
.de_BufMemType
= parentDG
.dg_BufMemType
;
681 partitionDE
.de_TableSize
= DE_DOSTYPE
;
682 partitionDE
.de_Reserved
= 2;
683 partitionDE
.de_HighCyl
= highcyl
;
684 partitionDE
.de_LowCyl
= lowcyl
;
685 partitionDE
.de_NumBuffers
= 100;
686 partitionDE
.de_MaxTransfer
= 0xFFFFFF;
687 partitionDE
.de_Mask
= 0xFFFFFFFE;
689 D(bug("[C:Partition] SizeBlock %ld\n", partitionDE
.de_SizeBlock
));
690 D(bug("[C:Partition] Surfaces %ld\n", partitionDE
.de_Surfaces
));
691 D(bug("[C:Partition] BlocksPerTrack %ld\n", partitionDE
.de_BlocksPerTrack
));
692 D(bug("[C:Partition] BufMemType %ld\n", partitionDE
.de_BufMemType
));
693 D(bug("[C:Partition] TableSize %ld\n", partitionDE
.de_TableSize
));
694 D(bug("[C:Partition] Reserved %ld\n", partitionDE
.de_Reserved
));
695 D(bug("[C:Partition] HighCyl %ld\n", partitionDE
.de_HighCyl
));
696 D(bug("[C:Partition] LowCyl %ld\n", partitionDE
.de_LowCyl
));
698 partition
= AddPartitionTags
702 PT_DOSENVEC
, (IPTR
) &partitionDE
,
703 PT_TYPE
, (IPTR
) type
,
704 PT_NAME
, (IPTR
) name
,
705 PT_BOOTABLE
, bootable
,
714 /* Convert a size in megabytes into a cylinder count. The figure returned
715 is rounded down to avoid breaching maximum filesystem sizes. */
716 static ULONG
MBsToCylinders(ULONG size
, struct DosEnvec
*de
)
724 cyls
= bytes
/ (UQUAD
)(de
->de_SizeBlock
* sizeof(ULONG
))
725 / de
->de_BlocksPerTrack
/ de
->de_Surfaces
;
730 #define ZEROBUFFSIZE 4096
732 /* Go through whole partition tree and WIPE each and every entry */
733 static LONG
RecurviseDestroyPartitions(struct PartitionHandle
*root
)
739 struct PartitionHandle
*partition
;
740 ForeachNode(&root
->table
->list
, partition
)
742 if (OpenPartitionTable(partition
) == 0)
744 error
+= RecurviseDestroyPartitions(partition
);
748 APTR buffer
= AllocMem(ZEROBUFFSIZE
, MEMF_CLEAR
);
749 /* Damage first blocks of partition */
750 WritePartitionDataQ(partition
, buffer
, ZEROBUFFSIZE
, 0);
751 FreeMem(buffer
, ZEROBUFFSIZE
);
756 error
+= DestroyPartitionTable(root
);