summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock/src/bdpart-create.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libblock/src/bdpart-create.c')
-rw-r--r--cpukit/libblock/src/bdpart-create.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/cpukit/libblock/src/bdpart-create.c b/cpukit/libblock/src/bdpart-create.c
new file mode 100644
index 0000000000..dc93522c19
--- /dev/null
+++ b/cpukit/libblock/src/bdpart-create.c
@@ -0,0 +1,160 @@
+/**
+ * @file
+ *
+ * @ingroup rtems_bdpart
+ *
+ * Block device partition management.
+ */
+
+/*
+ * Copyright (c) 2009, 2010
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/bdpart.h>
+
+rtems_status_code rtems_bdpart_create(
+ const char *disk_name,
+ const rtems_bdpart_format *format,
+ rtems_bdpart_partition *pt,
+ const unsigned *dist,
+ size_t count
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ bool dos_compatibility = format != NULL
+ && format->type == RTEMS_BDPART_FORMAT_MBR
+ && format->mbr.dos_compatibility;
+ rtems_blkdev_bnum disk_end = 0;
+ rtems_blkdev_bnum pos = 0;
+ rtems_blkdev_bnum dist_sum = 0;
+ rtems_blkdev_bnum record_space =
+ dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
+ rtems_blkdev_bnum overhead = 0;
+ rtems_blkdev_bnum free_space = 0;
+ dev_t disk = 0;
+ size_t i = 0;
+
+ /* Check if we have something to do */
+ if (count == 0) {
+ /* Nothing to do */
+ return RTEMS_SUCCESSFUL;
+ }
+
+ /* Check parameter */
+ if (format == NULL || pt == NULL || dist == NULL) {
+ return RTEMS_INVALID_ADDRESS;
+ }
+
+ /* Get disk data */
+ sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+
+ /* Get distribution sum and check for overflow */
+ for (i = 0; i < count; ++i) {
+ unsigned prev_sum = dist_sum;
+
+ dist_sum += dist [i];
+
+ if (dist_sum < prev_sum) {
+ return RTEMS_INVALID_NUMBER;
+ }
+
+ if (dist [i] == 0) {
+ return RTEMS_INVALID_NUMBER;
+ }
+ }
+
+ /* Check format */
+ if (format->type != RTEMS_BDPART_FORMAT_MBR) {
+ return RTEMS_NOT_IMPLEMENTED;
+ }
+
+ /* Align end of disk on cylinder boundary if necessary */
+ if (dos_compatibility) {
+ disk_end -= (disk_end % record_space);
+ }
+
+ /*
+ * We need at least space for the MBR and the compatibility space for the
+ * first primary partition.
+ */
+ overhead += record_space;
+
+ /*
+ * In case we need an extended partition and logical partitions we have to
+ * account for the space of each EBR.
+ */
+ if (count > 4) {
+ overhead += (count - 3) * record_space;
+ }
+
+ /*
+ * Account space to align every partition on cylinder boundaries if
+ * necessary.
+ */
+ if (dos_compatibility) {
+ overhead += (count - 1) * record_space;
+ }
+
+ /* Check disk space */
+ if ((overhead + count) > disk_end) {
+ return RTEMS_IO_ERROR;
+ }
+
+ /* Begin of first primary partition */
+ pos = record_space;
+
+ /* Space for partitions */
+ free_space = disk_end - overhead;
+
+ for (i = 0; i < count; ++i) {
+ rtems_bdpart_partition *p = pt + i;
+
+ /* Partition size */
+ rtems_blkdev_bnum s = free_space * dist [i];
+ if (s < free_space || s < dist [i]) {
+ /* TODO: Calculate without overflow */
+ return RTEMS_INVALID_NUMBER;
+ }
+ s /= dist_sum;
+
+ /* Ensure that the partition is not empty */
+ if (s == 0) {
+ s = 1;
+ }
+
+ /* Align partition upwards */
+ s += record_space - (s % record_space);
+
+ /* Partition begin and end */
+ p->begin = pos;
+ pos += s;
+ p->end = pos;
+
+ /* Reserve space for the EBR if necessary */
+ if (count > 4 && i > 2) {
+ p->begin += record_space;
+ }
+ }
+
+ /* Expand the last partition to the disk end */
+ pt [count - 1].end = disk_end;
+
+ return RTEMS_SUCCESSFUL;
+}