source: rtems/cpukit/libblock/src/bdpart.c @ 1560d12

4.104.115
Last change on this file since 1560d12 was 463b8df, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/13/09 at 15:40:03

Add attribute((unused)) to suppress warnings.

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