source: rtems/cpukit/libblock/src/bdpart.c @ 9fc1ebd

4.104.115
Last change on this file since 9fc1ebd was 694c3ac6, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/28/10 at 03:14:08

Add HAVE_CONFIG_H support to let files receive configure defines.

  • Property mode set to 100644
File size: 28.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bdpart
5 *
6 * Block device partition management.
7 */
8
9/*
10 * Copyright (c) 2009
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <inttypes.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
34#include <rtems/bdbuf.h>
35#include <rtems/bdpart.h>
36#include <rtems/dosfs.h>
37#include <rtems/endian.h>
38#include <rtems/fsmount.h>
39
40#define RTEMS_BDPART_MBR_PARTITION_TYPE( type) \
41  { \
42    (type), 0xa2U, 0x2eU, 0x38U, \
43    0x38U, 0xb5U, 0xdeU, 0x11U, \
44    0xbcU, 0x13U, 0x00U, 0x1dU, \
45    0x09U, 0xb0U, 0x5fU, 0xa4U \
46  }
47
48#define RTEMS_BDPART_BLOCK_SIZE 512
49
50#define RTEMS_BDPART_MBR_CYLINDER_SIZE 63
51
52#define RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE 16
53
54#define RTEMS_BDPART_MBR_OFFSET_TABLE_0 446
55
56#define RTEMS_BDPART_MBR_OFFSET_TABLE_1 \
57  (RTEMS_BDPART_MBR_OFFSET_TABLE_0 + RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE)
58
59#define RTEMS_BDPART_MBR_OFFSET_DISK_ID 440
60
61#define RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0 510
62
63#define RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1 511
64
65#define RTEMS_BDPART_MBR_SIGNATURE_0 0x55U
66
67#define RTEMS_BDPART_MBR_SIGNATURE_1 0xaaU
68
69#define RTEMS_BDPART_MBR_OFFSET_BEGIN 8
70
71#define RTEMS_BDPART_MBR_OFFSET_SIZE 12
72
73#define RTEMS_BDPART_MBR_OFFSET_TYPE 4
74
75#define RTEMS_BDPART_MBR_OFFSET_FLAGS 0
76
77#define RTEMS_BDPART_PARTITION_READ_MAX 32
78
79static const uuid_t RTEMS_BDPART_MBR_MASTER_TYPE =
80  RTEMS_BDPART_MBR_PARTITION_TYPE( RTEMS_BDPART_MBR_EMPTY);
81
82void rtems_bdpart_to_partition_type( uint8_t mbr_type, uuid_t type)
83{
84  type [0] = mbr_type;
85  memcpy( type + 1, RTEMS_BDPART_MBR_MASTER_TYPE + 1, sizeof( uuid_t) - 1);
86}
87
88static uint8_t rtems_bdpart_mbr_partition_type(
89  const uuid_t type
90)
91{
92  return type [0];
93}
94
95bool rtems_bdpart_to_mbr_partition_type(
96  const uuid_t type,
97  uint8_t *mbr_type
98)
99{
100  *mbr_type = rtems_bdpart_mbr_partition_type( type);
101
102  return memcmp(
103    type + 1,
104    RTEMS_BDPART_MBR_MASTER_TYPE + 1,
105    sizeof( uuid_t) - 1
106  ) == 0;
107}
108
109static void rtems_bdpart_type_to_string(
110  const uuid_t type,
111  char str [37]
112)
113{
114  uuid_unparse_lower( type, str);
115}
116
117/*
118 * FIXME: This code should the deviceio interface and not the bdbug interface.
119 */
120static rtems_status_code rtems_bdpart_get_disk_data(
121  const char *disk_name,
122  dev_t *disk,
123  rtems_blkdev_bnum *disk_end
124)
125{
126  rtems_status_code sc = RTEMS_SUCCESSFUL;
127  int rv = 0;
128  rtems_blkdev_bnum disk_begin = 0;
129  rtems_blkdev_bnum block_size = 0;
130  rtems_disk_device *dd = NULL;
131  struct stat st;
132
133  /* Get disk handle */
134  rv = stat( disk_name, &st);
135  if (rv != 0) {
136    return RTEMS_INVALID_NAME;
137  }
138  *disk = st.st_rdev;
139
140  /* Get disk begin, end and block size */
141  dd = rtems_disk_obtain( *disk);
142  if (dd == NULL) {
143    return RTEMS_INVALID_NAME;
144  }
145  disk_begin = dd->start;
146  *disk_end = dd->size;
147  block_size = dd->block_size;
148  sc = rtems_disk_release( dd);
149  if (sc != RTEMS_SUCCESSFUL) {
150    return sc;
151  }
152
153  /* Check block size */
154  if (block_size < RTEMS_BDPART_BLOCK_SIZE) {
155    return RTEMS_IO_ERROR;
156  }
157
158  /* Check that we have do not have a logical disk */
159  if (disk_begin != 0) {
160    return RTEMS_IO_ERROR;
161  }
162
163  return RTEMS_SUCCESSFUL;
164}
165
166static int rtems_bdpart_partition_compare( const void *aa, const void *bb)
167{
168  const rtems_bdpart_partition *a = aa;
169  const rtems_bdpart_partition *b = bb;
170
171  if (a->begin < b->begin) {
172    return -1;
173  } else if (a->begin == b->begin) {
174    return 0;
175  } else {
176    return 1;
177  }
178}
179
180static bool rtems_bdpart_is_valid_record( const uint8_t *data)
181{
182  return data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0]
183      == RTEMS_BDPART_MBR_SIGNATURE_0
184    && data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1]
185      == RTEMS_BDPART_MBR_SIGNATURE_1;
186}
187
188static rtems_blkdev_bnum rtems_bdpart_next_ebr( const uint8_t *data)
189{
190  rtems_blkdev_bnum begin =
191    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
192  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
193
194  if (type == RTEMS_BDPART_MBR_EXTENDED) {
195    return begin;
196  } else {
197    return 0;
198  }
199}
200
201static rtems_status_code rtems_bdpart_read_mbr_partition(
202  const uint8_t *data,
203  rtems_bdpart_partition **p,
204  const rtems_bdpart_partition *p_end,
205  rtems_blkdev_bnum *ep_begin
206)
207{
208  rtems_blkdev_bnum begin =
209    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
210  rtems_blkdev_bnum size =
211    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_SIZE);
212  rtems_blkdev_bnum end = begin + size;
213  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
214
215  if (type == RTEMS_BDPART_MBR_EMPTY) {
216    return RTEMS_SUCCESSFUL;
217  } else if (*p == p_end) {
218    return RTEMS_TOO_MANY;
219  } else if (begin >= end) {
220    return RTEMS_IO_ERROR;
221  } else if (type == RTEMS_BDPART_MBR_EXTENDED) {
222    if (ep_begin != NULL) {
223      *ep_begin = begin;
224    }
225  } else {
226    /* Increment partition index */
227    ++(*p);
228
229    /* Clear partition */
230    memset( *p, 0, sizeof( rtems_bdpart_partition));
231
232    /* Set values */
233    (*p)->begin = begin;
234    (*p)->end = end;
235    rtems_bdpart_to_partition_type( type, (*p)->type);
236    (*p)->flags = data [RTEMS_BDPART_MBR_OFFSET_FLAGS];
237  }
238
239  return RTEMS_SUCCESSFUL;
240}
241
242static void rtems_bdpart_write_mbr_partition(
243  uint8_t *data,
244  uint32_t begin,
245  uint32_t size,
246  uint8_t type,
247  uint8_t flags
248)
249{
250  rtems_uint32_to_little_endian( begin, data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
251  rtems_uint32_to_little_endian( size, data + RTEMS_BDPART_MBR_OFFSET_SIZE);
252  data [RTEMS_BDPART_MBR_OFFSET_TYPE] = type;
253  data [RTEMS_BDPART_MBR_OFFSET_FLAGS] = flags;
254}
255
256static rtems_status_code rtems_bdpart_read_record(
257  dev_t disk,
258  rtems_blkdev_bnum index,
259  rtems_bdbuf_buffer **block
260)
261{
262  rtems_status_code sc = RTEMS_SUCCESSFUL;
263
264  /* Release previous block if necessary */
265  if (*block != NULL) {
266    sc = rtems_bdbuf_release( *block);
267    if (sc != RTEMS_SUCCESSFUL) {
268      return sc;
269    }
270  }
271
272  /* Read the record block */
273  sc = rtems_bdbuf_read( disk, index, block);
274  if (sc != RTEMS_SUCCESSFUL) {
275    return sc;
276  }
277
278  /* just in case block did not get filled in */
279  if ( *block == NULL ) {
280    return RTEMS_INVALID_ADDRESS;
281  }
282
283  /* Check MBR signature */
284  if (!rtems_bdpart_is_valid_record( (*block)->buffer)) {
285    return RTEMS_IO_ERROR;
286  }
287
288  return RTEMS_SUCCESSFUL;
289}
290
291static rtems_status_code rtems_bdpart_new_record(
292  dev_t disk,
293  rtems_blkdev_bnum index,
294  rtems_bdbuf_buffer **block
295)
296{
297  rtems_status_code sc = RTEMS_SUCCESSFUL;
298
299  /* Synchronize previous block if necessary */
300  if (*block != NULL) {
301    sc = rtems_bdbuf_sync( *block);
302    if (sc != RTEMS_SUCCESSFUL) {
303      return sc;
304    }
305  }
306
307  /* Read the new record block (this accounts for disk block sizes > 512) */
308  sc = rtems_bdbuf_read( disk, index, block);
309  if (sc != RTEMS_SUCCESSFUL) {
310    return sc;
311  }
312
313  /* just in case block did not get filled in */
314  if ( *block == NULL ) {
315    return RTEMS_INVALID_ADDRESS;
316  }
317
318  /* Clear record */
319  memset( (*block)->buffer, 0, RTEMS_BDPART_BLOCK_SIZE);
320
321  /* Write signature */
322  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0] =
323    RTEMS_BDPART_MBR_SIGNATURE_0;
324  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1] =
325    RTEMS_BDPART_MBR_SIGNATURE_1;
326
327  return RTEMS_SUCCESSFUL;
328}
329
330rtems_status_code rtems_bdpart_read(
331  const char *disk_name,
332  rtems_bdpart_format *format,
333  rtems_bdpart_partition *pt,
334  size_t *count
335)
336{
337  rtems_status_code sc = RTEMS_SUCCESSFUL;
338  rtems_status_code esc = RTEMS_SUCCESSFUL;
339  rtems_bdbuf_buffer *block = NULL;
340  rtems_bdpart_partition *p = pt - 1;
341  const rtems_bdpart_partition *p_end = pt + (count != NULL ? *count : 0);
342  rtems_blkdev_bnum ep_begin = 0; /* Extended partition begin */
343  rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
344  rtems_blkdev_bnum disk_end = 0;
345  dev_t disk = 0;
346  size_t i = 0;
347  const uint8_t *data = NULL;
348
349  /* Check parameter */
350  if (format == NULL || pt == NULL || count == NULL) {
351    return RTEMS_INVALID_ADDRESS;
352  }
353
354  /* Set count to a save value */
355  *count = 0;
356
357  /* Get disk data */
358  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
359  if (sc != RTEMS_SUCCESSFUL) {
360    return sc;
361  }
362
363  /* Read MBR */
364  sc = rtems_bdpart_read_record( disk, 0, &block);
365  if (sc != RTEMS_SUCCESSFUL) {
366    esc = sc;
367    goto cleanup;
368  }
369
370  /* Read the first partition entry */
371  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
372  sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
373  if (sc != RTEMS_SUCCESSFUL) {
374    esc = sc;
375    goto cleanup;
376  }
377
378  /* Determine if we have a MBR or GPT format */
379  if (rtems_bdpart_mbr_partition_type( p->type) == RTEMS_BDPART_MBR_GPT) {
380    esc = RTEMS_NOT_IMPLEMENTED;
381    goto cleanup;
382  }
383
384  /* Set format */
385  format->type = RTEMS_BDPART_FORMAT_MBR;
386  format->mbr.disk_id = rtems_uint32_from_little_endian(
387    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
388  );
389  format->mbr.dos_compatibility = true;
390
391  /* Iterate through the rest of the primary partition table */
392  for (i = 1; i < 4; ++i) {
393    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
394
395    sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
396    if (sc != RTEMS_SUCCESSFUL) {
397      esc = sc;
398      goto cleanup;
399    }
400  }
401
402  /* Iterate through the logical partitions within the extended partition */
403  ebr = ep_begin;
404  while (ebr != 0) {
405    rtems_blkdev_bnum tmp = 0;
406
407    /* Read EBR */
408    sc = rtems_bdpart_read_record( disk, ebr, &block);
409    if (sc != RTEMS_SUCCESSFUL) {
410      esc = sc;
411      goto cleanup;
412    }
413
414    /* Read first partition entry */
415    sc = rtems_bdpart_read_mbr_partition(
416      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
417      &p,
418      p_end,
419      NULL
420    );
421    if (sc != RTEMS_SUCCESSFUL) {
422      esc = sc;
423      goto cleanup;
424    }
425
426    /* Adjust partition begin */
427    tmp = p->begin + ebr;
428    if (tmp > p->begin) {
429      p->begin = tmp;
430    } else {
431      esc = RTEMS_IO_ERROR;
432      goto cleanup;
433    }
434
435    /* Adjust partition end */
436    tmp = p->end + ebr;
437    if (tmp > p->end) {
438      p->end = tmp;
439    } else {
440      esc = RTEMS_IO_ERROR;
441      goto cleanup;
442    }
443
444    /* Read second partition entry for next EBR block */
445    ebr = rtems_bdpart_next_ebr(
446      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1
447    );
448    if (ebr != 0) {
449      /* Adjust partition EBR block index */
450      tmp = ebr + ep_begin;
451      if (tmp > ebr) {
452        ebr = tmp;
453      } else {
454        esc = RTEMS_IO_ERROR;
455        goto cleanup;
456      }
457    }
458  }
459
460  /* Return partition count */
461  *count = (size_t) (p - pt + 1);
462
463cleanup:
464
465  if (block != NULL) {
466    rtems_bdbuf_release( block);
467  }
468
469  return esc;
470}
471
472void rtems_bdpart_sort( rtems_bdpart_partition *pt, size_t count)
473{
474  qsort( pt, count, sizeof( *pt), rtems_bdpart_partition_compare);
475}
476
477rtems_status_code rtems_bdpart_write(
478  const char *disk_name,
479  const rtems_bdpart_format *format,
480  const rtems_bdpart_partition *pt,
481  size_t count
482)
483{
484  rtems_status_code sc = RTEMS_SUCCESSFUL;
485  rtems_status_code esc = RTEMS_SUCCESSFUL;
486  bool dos_compatibility = format != NULL
487    && format->type == RTEMS_BDPART_FORMAT_MBR
488    && format->mbr.dos_compatibility;
489  rtems_bdbuf_buffer *block = NULL;
490  rtems_blkdev_bnum disk_end = 0;
491  rtems_blkdev_bnum record_space =
492    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
493  dev_t disk = 0;
494  size_t ppc = 0; /* Primary partition count */
495  size_t i = 0;
496  uint8_t *data = NULL;
497
498  /* Check if we have something to do */
499  if (count == 0) {
500    /* Nothing to do */
501    return RTEMS_SUCCESSFUL;
502  }
503
504  /* Check parameter */
505  if (format == NULL || pt == NULL) {
506    return RTEMS_INVALID_ADDRESS;
507  }
508
509  /* Get disk data */
510  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
511  if (sc != RTEMS_SUCCESSFUL) {
512    return sc;
513  }
514
515  /* Align end of disk on cylinder boundary if necessary */
516  if (dos_compatibility) {
517    disk_end -= (disk_end % record_space);
518  }
519
520  /* Check that we have a consistent partition table */
521  for (i = 0; i < count; ++i) {
522    const rtems_bdpart_partition *p = pt + i;
523
524    /* Check that begin and end are proper within the disk */
525    if (p->begin >= disk_end || p->end > disk_end) {
526      esc = RTEMS_INVALID_NUMBER;
527      goto cleanup;
528    }
529
530    /* Check that begin and end are valid */
531    if (p->begin >= p->end) {
532      esc = RTEMS_INVALID_NUMBER;
533      goto cleanup;
534    }
535
536    /* Check that partitions do not overlap */
537    if (i > 0 && pt [i - 1].end > p->begin) {
538      esc = RTEMS_INVALID_NUMBER;
539      goto cleanup;
540    }
541  }
542
543  /* Check format */
544  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
545    esc = RTEMS_NOT_IMPLEMENTED;
546    goto cleanup;
547  }
548
549  /*
550   * Set primary partition count.  If we have more than four partitions we need
551   * an extended partition which will contain the partitions of number four and
552   * above as logical partitions.  If we have four or less partitions we can
553   * use the primary partition table.
554   */
555  ppc = count <= 4 ? count : 3;
556
557  /*
558   * Check that the first primary partition starts at head one and sector one
559   * under the virtual one head and 63 sectors geometry if necessary.
560   */
561  if (dos_compatibility && pt [0].begin != RTEMS_BDPART_MBR_CYLINDER_SIZE) {
562    esc = RTEMS_INVALID_NUMBER;
563    goto cleanup;
564  }
565
566  /*
567   * Check that we have enough space for the EBRs.  The partitions with number
568   * four and above are logical partitions if we have more than four partitions
569   * in total.  The logical partitions are contained in the extended partition.
570   * Each logical partition is described via one EBR preceding the partition.
571   * The space for the EBR and maybe some space which is needed for DOS
572   * compatibility resides between the partitions.  So there have to be gaps of
573   * the appropriate size between the partitions.
574   */
575  for (i = ppc; i < count; ++i) {
576    if ((pt [i].begin - pt [i - 1].end) < record_space) {
577      esc = RTEMS_INVALID_NUMBER;
578      goto cleanup;
579    }
580  }
581
582  /* Check that we can convert the parition descriptions to the MBR format */
583  for (i = 0; i < count; ++i) {
584    uint8_t type = 0;
585
586    const rtems_bdpart_partition *p = pt + i;
587
588    /* Check type */
589    if (!rtems_bdpart_to_mbr_partition_type( p->type, &type)) {
590      esc =  RTEMS_INVALID_ID;
591      goto cleanup;
592    }
593
594    /* Check flags */
595    if (p->flags > 0xffU) {
596      esc = RTEMS_INVALID_ID;
597      goto cleanup;
598    }
599
600    /* Check ID */
601    /* TODO */
602  }
603
604  /* New MBR */
605  sc = rtems_bdpart_new_record( disk, 0, &block);
606  if (sc != RTEMS_SUCCESSFUL) {
607    esc = sc;
608    goto cleanup;
609  }
610
611  /* Write disk ID */
612  rtems_uint32_to_little_endian(
613    format->mbr.disk_id,
614    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
615  );
616
617  /* Write primary partition table */
618  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
619  for (i = 0; i < ppc; ++i) {
620    const rtems_bdpart_partition *p = pt + i;
621
622    /* Write partition entry */
623    rtems_bdpart_write_mbr_partition(
624      data,
625      p->begin,
626      p->end - p->begin,
627      rtems_bdpart_mbr_partition_type( p->type),
628      (uint8_t) p->flags
629    );
630
631    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
632  }
633
634  /* Write extended partition with logical partitions if necessary */
635  if (ppc != count) {
636    rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
637
638    /* Begin of extended partition */
639    rtems_blkdev_bnum ep_begin = pt [ppc].begin - record_space;
640
641    /* Write extended partition */
642    rtems_bdpart_write_mbr_partition(
643      data,
644      ep_begin,
645      disk_end - ep_begin,
646      RTEMS_BDPART_MBR_EXTENDED,
647      0
648    );
649
650    /* Write logical partitions */
651    for (i = ppc; i < count; ++i) {
652      const rtems_bdpart_partition *p = pt + i;
653
654      /* Write second partition entry */
655      if (i > ppc) {
656        rtems_blkdev_bnum begin = p->begin - record_space;
657
658        rtems_bdpart_write_mbr_partition(
659          block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1,
660          begin - ep_begin,
661          disk_end - begin,
662          RTEMS_BDPART_MBR_EXTENDED,
663          0
664        );
665      }
666
667      /* New EBR */
668      ebr = p->begin - record_space;
669      sc = rtems_bdpart_new_record( disk, ebr, &block);
670      if (sc != RTEMS_SUCCESSFUL) {
671        esc = sc;
672        goto cleanup;
673      }
674
675      /* Write first partition entry */
676      rtems_bdpart_write_mbr_partition(
677        block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
678        record_space,
679        p->end - p->begin,
680        rtems_bdpart_mbr_partition_type( p->type),
681        (uint8_t) p->flags
682      );
683    }
684  }
685
686cleanup:
687
688  if (block != NULL) {
689    rtems_bdbuf_sync( block);
690  }
691
692  return esc;
693}
694
695rtems_status_code rtems_bdpart_create(
696  const char *disk_name,
697  const rtems_bdpart_format *format,
698  rtems_bdpart_partition *pt,
699  const unsigned *dist,
700  size_t count
701)
702{
703  rtems_status_code sc = RTEMS_SUCCESSFUL;
704  bool dos_compatibility = format != NULL
705    && format->type == RTEMS_BDPART_FORMAT_MBR
706    && format->mbr.dos_compatibility;
707  rtems_blkdev_bnum disk_end = 0;
708  rtems_blkdev_bnum pos = 0;
709  rtems_blkdev_bnum dist_sum = 0;
710  rtems_blkdev_bnum record_space =
711    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
712  rtems_blkdev_bnum overhead = 0;
713  rtems_blkdev_bnum free_space = 0;
714  dev_t disk = 0;
715  size_t i = 0;
716
717  /* Check if we have something to do */
718  if (count == 0) {
719    /* Nothing to do */
720    return RTEMS_SUCCESSFUL;
721  }
722
723  /* Check parameter */
724  if (format == NULL || pt == NULL || dist == NULL) {
725    return RTEMS_INVALID_ADDRESS;
726  }
727
728  /* Get disk data */
729  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
730  if (sc != RTEMS_SUCCESSFUL) {
731    return sc;
732  }
733
734  /* Get distribution sum and check for overflow */
735  for (i = 0; i < count; ++i) {
736    unsigned prev_sum = dist_sum;
737
738    dist_sum += dist [i];
739
740    if (dist_sum < prev_sum) {
741      return RTEMS_INVALID_NUMBER;
742    }
743
744    if (dist [i] == 0) {
745      return RTEMS_INVALID_NUMBER;
746    }
747  }
748
749  /* Check format */
750  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
751    return RTEMS_NOT_IMPLEMENTED;
752  }
753
754  /* Align end of disk on cylinder boundary if necessary */
755  if (dos_compatibility) {
756    disk_end -= (disk_end % record_space);
757  }
758
759  /*
760   * We need at least space for the MBR and the compatibility space for the
761   * first primary partition.
762   */
763  overhead += record_space;
764
765  /*
766   * In case we need an extended partition and logical partitions we have to
767   * account for the space of each EBR.
768   */
769  if (count > 4) {
770    overhead += (count - 3) * record_space;
771  }
772
773  /*
774   * Account space to align every partition on cylinder boundaries if
775   * necessary.
776   */
777  if (dos_compatibility) {
778    overhead += (count - 1) * record_space;
779  }
780
781  /* Check disk space */
782  if ((overhead + count) > disk_end) {
783    return RTEMS_IO_ERROR;
784  }
785
786  /* Begin of first primary partition */
787  pos = record_space;
788
789  /* Space for partitions */
790  free_space = disk_end - overhead;
791
792  for (i = 0; i < count; ++i) {
793    rtems_bdpart_partition *p = pt + i;
794
795    /* Partition size */
796    rtems_blkdev_bnum s = free_space * dist [i];
797    if (s < free_space || s < dist [i]) {
798      /* TODO: Calculate without overflow */
799      return RTEMS_INVALID_NUMBER;
800    }
801    s /= dist_sum;
802
803    /* Ensure that the partition is not empty */
804    if (s == 0) {
805      s = 1;
806    }
807
808    /* Align partition upwards */
809    s += record_space - (s % record_space);
810
811    /* Partition begin and end */
812    p->begin = pos;
813    pos += s;
814    p->end = pos;
815
816    /* Reserve space for the EBR if necessary */
817    if (count > 4 && i > 2) {
818      p->begin += record_space;
819    }
820  }
821
822  /* Expand the last partition to the disk end */
823  pt [count - 1].end = disk_end;
824
825  return RTEMS_SUCCESSFUL;
826}
827
828#define RTEMS_BDPART_NUMBER_SIZE 4
829
830rtems_status_code rtems_bdpart_register(
831  const char *disk_name,
832  const rtems_bdpart_partition *pt,
833  size_t count
834)
835{
836  rtems_status_code sc = RTEMS_SUCCESSFUL;
837  rtems_status_code esc = RTEMS_SUCCESSFUL;
838  rtems_device_major_number major = 0;
839  rtems_device_minor_number minor = 0;
840  rtems_blkdev_bnum disk_end = 0;
841  dev_t disk = 0;
842  dev_t logical_disk = 0;
843  char *logical_disk_name = NULL;
844  char *logical_disk_marker = NULL;
845  size_t disk_name_size = strlen( disk_name);
846  size_t i = 0;
847
848  /* Get disk data */
849  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
850  if (sc != RTEMS_SUCCESSFUL) {
851    return sc;
852  }
853
854  /* Get the disk device identifier */
855  rtems_filesystem_split_dev_t( disk, major, minor);
856
857  /* Create logical disk name */
858  logical_disk_name = malloc( disk_name_size + RTEMS_BDPART_NUMBER_SIZE);
859  if (logical_disk_name == NULL) {
860    return RTEMS_NO_MEMORY;
861  }
862  strncpy( logical_disk_name, disk_name, disk_name_size);
863  logical_disk_marker = logical_disk_name + disk_name_size;
864
865  /* Create a logical disk for each partition */
866  for (i = 0; i < count; ++i) {
867    const rtems_bdpart_partition *p = pt + i;
868    int rv = 0;
869
870    /* New minor number */
871    ++minor;
872
873    /* Create a new device identifier */
874    logical_disk = rtems_filesystem_make_dev_t( major, minor);
875
876    /* Set partition number for logical disk name */
877    rv = snprintf( logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
878    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
879      esc = RTEMS_INVALID_NAME;
880      goto cleanup;
881    }
882
883    /* Create logical disk */
884    sc = rtems_disk_create_log(
885      logical_disk,
886      disk,
887      p->begin,
888      p->end - p->begin,
889      logical_disk_name
890    );
891    if (sc != RTEMS_SUCCESSFUL) {
892      esc = sc;
893      goto cleanup;
894    }
895  }
896
897cleanup:
898
899  free( logical_disk_name);
900
901  return esc;
902}
903
904rtems_status_code rtems_bdpart_register_from_disk( const char *disk_name)
905{
906  rtems_status_code sc = RTEMS_SUCCESSFUL;
907  rtems_bdpart_format format;
908  rtems_bdpart_partition pt [RTEMS_BDPART_PARTITION_NUMBER_HINT];
909  size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT;
910
911  /* Read partitions */
912  sc = rtems_bdpart_read( disk_name, &format, pt, &count);
913  if (sc != RTEMS_SUCCESSFUL) {
914    return sc;
915  }
916
917  /* Register partitions */
918  return rtems_bdpart_register( disk_name, pt, count);
919}
920
921rtems_status_code rtems_bdpart_unregister(
922  const char *disk_name,
923  const rtems_bdpart_partition *pt __attribute__((unused)),
924  size_t count
925)
926{
927  rtems_status_code sc = RTEMS_SUCCESSFUL;
928  rtems_device_major_number major = 0;
929  rtems_device_minor_number minor = 0;
930  rtems_blkdev_bnum disk_end = 0;
931  dev_t disk = 0;
932  dev_t logical_disk = 0;
933  size_t i = 0;
934
935  /* Get disk data */
936  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
937  if (sc != RTEMS_SUCCESSFUL) {
938    return sc;
939  }
940
941  /* Get the disk device identifier */
942  rtems_filesystem_split_dev_t( disk, major, minor);
943
944  /* Create a logical disk for each partition */
945  for (i = 0; i < count; ++i) {
946    /* New minor number */
947    ++minor;
948
949    /* Get the device identifier */
950    logical_disk = rtems_filesystem_make_dev_t( major, minor);
951
952    /* Delete logical disk */
953    sc = rtems_disk_delete( logical_disk);
954    if (sc != RTEMS_SUCCESSFUL) {
955      return sc;
956    }
957  }
958
959  return RTEMS_SUCCESSFUL;
960}
961
962rtems_status_code rtems_bdpart_mount(
963  const char *disk_name,
964  const rtems_bdpart_partition *pt __attribute__((unused)),
965  size_t count,
966  const char *mount_base
967)
968{
969  rtems_status_code esc = RTEMS_SUCCESSFUL;
970  const char *disk_file_name = strrchr( disk_name, '/');
971  char *logical_disk_name = NULL;
972  char *logical_disk_marker = NULL;
973  char *mount_point = NULL;
974  char *mount_marker = NULL;
975  size_t disk_file_name_size = 0;
976  size_t disk_name_size = strlen( disk_name);
977  size_t mount_base_size = strlen( mount_base);
978  size_t i = 0;
979
980  /* Create logical disk name base */
981  logical_disk_name = malloc( disk_name_size + RTEMS_BDPART_NUMBER_SIZE);
982  if (logical_disk_name == NULL) {
983    return RTEMS_NO_MEMORY;
984  }
985  strncpy( logical_disk_name, disk_name, disk_name_size);
986
987  /* Get disk file name */
988  if (disk_file_name != NULL) {
989    disk_file_name += 1;
990    disk_file_name_size = strlen( disk_file_name);
991  } else {
992    disk_file_name = disk_name;
993    disk_file_name_size = disk_name_size;
994  }
995
996  /* Create mount point base */
997  mount_point = malloc( mount_base_size + 1 + disk_file_name_size + RTEMS_BDPART_NUMBER_SIZE);
998  if (mount_point == NULL) {
999    esc = RTEMS_NO_MEMORY;
1000    goto cleanup;
1001  }
1002  strncpy( mount_point, mount_base, mount_base_size);
1003  mount_point [mount_base_size] = '/';
1004  strncpy( mount_point + mount_base_size + 1, disk_file_name, disk_file_name_size);
1005
1006  /* Markers */
1007  logical_disk_marker = logical_disk_name + disk_name_size;
1008  mount_marker = mount_point + mount_base_size + 1 + disk_file_name_size;
1009
1010  /* Mount supported file systems for each partition */
1011  for (i = 0; i < count; ++i) {
1012    /* Create logical disk name */
1013    int rv = snprintf( logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
1014    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
1015      esc = RTEMS_INVALID_NAME;
1016      goto cleanup;
1017    }
1018
1019    /* Create mount point */
1020    strncpy( mount_marker, logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE);
1021    rv = rtems_fsmount_create_mount_point( mount_point);
1022    if (rv != 0) {
1023      esc = RTEMS_IO_ERROR;
1024      goto cleanup;
1025    }
1026
1027    /* Mount */
1028    rv = mount(
1029      NULL,
1030      &msdos_ops,
1031      0,
1032      logical_disk_name,
1033      mount_point
1034    );
1035    if (rv != 0) {
1036      rmdir( mount_point);
1037    }
1038  }
1039
1040cleanup:
1041
1042  free( logical_disk_name);
1043  free( mount_point);
1044
1045  return esc;
1046}
1047
1048rtems_status_code rtems_bdpart_unmount(
1049  const char *disk_name,
1050  const rtems_bdpart_partition *pt __attribute__((unused)),
1051  size_t count,
1052  const char *mount_base
1053)
1054{
1055  rtems_status_code esc = RTEMS_SUCCESSFUL;
1056  const char *disk_file_name = strrchr( disk_name, '/');
1057  char *mount_point = NULL;
1058  char *mount_marker = NULL;
1059  size_t disk_file_name_size = 0;
1060  size_t disk_name_size = strlen( disk_name);
1061  size_t mount_base_size = strlen( mount_base);
1062  size_t i = 0;
1063
1064  /* Get disk file name */
1065  if (disk_file_name != NULL) {
1066    disk_file_name += 1;
1067    disk_file_name_size = strlen( disk_file_name);
1068  } else {
1069    disk_file_name = disk_name;
1070    disk_file_name_size = disk_name_size;
1071  }
1072
1073  /* Create mount point base */
1074  mount_point = malloc( mount_base_size + 1 + disk_file_name_size + RTEMS_BDPART_NUMBER_SIZE);
1075  if (mount_point == NULL) {
1076    esc = RTEMS_NO_MEMORY;
1077    goto cleanup;
1078  }
1079  strncpy( mount_point, mount_base, mount_base_size);
1080  mount_point [mount_base_size] = '/';
1081  strncpy( mount_point + mount_base_size + 1, disk_file_name, disk_file_name_size);
1082
1083  /* Marker */
1084  mount_marker = mount_point + mount_base_size + 1 + disk_file_name_size;
1085
1086  /* Mount supported file systems for each partition */
1087  for (i = 0; i < count; ++i) {
1088    /* Create mount point */
1089    int rv = snprintf( mount_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
1090    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
1091      esc = RTEMS_INVALID_NAME;
1092      goto cleanup;
1093    }
1094
1095    /* Unmount */
1096    rv = unmount( mount_point);
1097    if (rv == 0) {
1098      /* Remove mount point */
1099      rv = rmdir( mount_point);
1100      if (rv != 0) {
1101        esc = RTEMS_IO_ERROR;
1102        goto cleanup;
1103      }
1104    }
1105  }
1106
1107cleanup:
1108
1109  free( mount_point);
1110
1111  return esc;
1112}
1113
1114void rtems_bdpart_dump( const rtems_bdpart_partition *pt, size_t count)
1115{
1116  size_t i = 0;
1117
1118  printf(
1119    "-------------------------------------------------------------------------------\n"
1120    "                                PARTITION TABLE\n"
1121    "------------+------------+-----------------------------------------------------\n"
1122    " BEGIN      | END        | TYPE\n"
1123    "------------+------------+-----------------------------------------------------\n"
1124  );
1125
1126  for (i = 0; i < count; ++i) {
1127    const rtems_bdpart_partition *p = pt + i;
1128    const char *type = NULL;
1129    char type_buffer [52];
1130    uint8_t type_mbr = 0;
1131
1132    if (rtems_bdpart_to_mbr_partition_type( p->type, &type_mbr)) {
1133      switch (type_mbr) {
1134        case RTEMS_BDPART_MBR_FAT_12:
1135          type = "FAT 12";
1136          break;
1137        case RTEMS_BDPART_MBR_FAT_16:
1138          type = "FAT 16";
1139          break;
1140        case RTEMS_BDPART_MBR_FAT_16_LBA:
1141          type = "FAT 16 LBA";
1142          break;
1143        case RTEMS_BDPART_MBR_FAT_32:
1144          type = "FAT 32";
1145          break;
1146        case RTEMS_BDPART_MBR_FAT_32_LBA:
1147          type = "FAT 32 LBA";
1148          break;
1149        case RTEMS_BDPART_MBR_DATA:
1150          type = "DATA";
1151          break;
1152        default:
1153          snprintf( type_buffer, sizeof( type_buffer), "0x%02" PRIx8, type_mbr);
1154          type = type_buffer;
1155          break;
1156      }
1157    } else {
1158      rtems_bdpart_type_to_string( p->type, type_buffer);
1159      type = type_buffer;
1160    }
1161
1162    printf(
1163      " %10lu | %10lu |%52s\n",
1164      (unsigned long) p->begin,
1165      (unsigned long) p->end,
1166      type
1167    );
1168  }
1169
1170  puts( "------------+------------+-----------------------------------------------------");
1171}
Note: See TracBrowser for help on using the repository browser.