source: rtems/cpukit/libblock/src/bdpart.c @ b5b07cad

4.104.115
Last change on this file since b5b07cad was b5b07cad, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 10/29/09 at 12:50:01
  • - Reorderd AVL node fields to save space
  • Fixed printf() formats. New structure for waiters synchronization. Added BDBUF_INVALID_DEV define. New error handling in rtems_bdbuf_init().
  • Release disk in case of an error.
  • 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    esc = sc;
353    goto cleanup;
354  }
355
356  /* Read the first partition entry */
357  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
358  sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
359  if (sc != RTEMS_SUCCESSFUL) {
360    esc = sc;
361    goto cleanup;
362  }
363
364  /* Determine if we have a MBR or GPT format */
365  if (rtems_bdpart_mbr_partition_type( p->type) == RTEMS_BDPART_MBR_GPT) {
366    esc = RTEMS_NOT_IMPLEMENTED;
367    goto cleanup;
368  }
369
370  /* Set format */
371  format->type = RTEMS_BDPART_FORMAT_MBR;
372  format->mbr.disk_id = rtems_uint32_from_little_endian(
373    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
374  );
375  format->mbr.dos_compatibility = true;
376
377  /* Iterate through the rest of the primary partition table */
378  for (i = 1; i < 4; ++i) {
379    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
380
381    sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
382    if (sc != RTEMS_SUCCESSFUL) {
383      esc = sc;
384      goto cleanup;
385    }
386  }
387
388  /* Iterate through the logical partitions within the extended partition */
389  ebr = ep_begin;
390  while (ebr != 0) {
391    rtems_blkdev_bnum tmp = 0;
392
393    /* Read EBR */
394    sc = rtems_bdpart_read_record( disk, ebr, &block);
395    if (sc != RTEMS_SUCCESSFUL) {
396      esc = sc;
397      goto cleanup;
398    }
399
400    /* Read first partition entry */
401    sc = rtems_bdpart_read_mbr_partition(
402      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
403      &p,
404      p_end,
405      NULL
406    );
407    if (sc != RTEMS_SUCCESSFUL) {
408      esc = sc;
409      goto cleanup;
410    }
411
412    /* Adjust partition begin */
413    tmp = p->begin + ebr;
414    if (tmp > p->begin) {
415      p->begin = tmp;
416    } else {
417      esc = RTEMS_IO_ERROR;
418      goto cleanup;
419    }
420
421    /* Adjust partition end */
422    tmp = p->end + ebr;
423    if (tmp > p->end) {
424      p->end = tmp;
425    } else {
426      esc = RTEMS_IO_ERROR;
427      goto cleanup;
428    }
429
430    /* Read second partition entry for next EBR block */
431    ebr = rtems_bdpart_next_ebr(
432      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1
433    );
434    if (ebr != 0) {
435      /* Adjust partition EBR block index */
436      tmp = ebr + ep_begin;
437      if (tmp > ebr) {
438        ebr = tmp;
439      } else {
440        esc = RTEMS_IO_ERROR;
441        goto cleanup;
442      }
443    }
444  }
445
446  /* Return partition count */
447  *count = (size_t) (p - pt + 1);
448
449cleanup:
450
451  if (block != NULL) {
452    rtems_bdbuf_release( block);
453  }
454
455  return esc;
456}
457
458void rtems_bdpart_sort( rtems_bdpart_partition *pt, size_t count)
459{
460  qsort( pt, count, sizeof( *pt), rtems_bdpart_partition_compare);
461}
462
463rtems_status_code rtems_bdpart_write(
464  const char *disk_name,
465  const rtems_bdpart_format *format,
466  const rtems_bdpart_partition *pt,
467  size_t count
468)
469{
470  rtems_status_code sc = RTEMS_SUCCESSFUL;
471  rtems_status_code esc = RTEMS_SUCCESSFUL;
472  bool dos_compatibility = format != NULL
473    && format->type == RTEMS_BDPART_FORMAT_MBR
474    && format->mbr.dos_compatibility;
475  rtems_bdbuf_buffer *block = NULL;
476  rtems_blkdev_bnum disk_end = 0;
477  rtems_blkdev_bnum record_space =
478    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
479  dev_t disk = 0;
480  size_t ppc = 0; /* Primary partition count */
481  size_t i = 0;
482  uint8_t *data = NULL;
483
484  /* Check if we have something to do */
485  if (count == 0) {
486    /* Nothing to do */
487    return RTEMS_SUCCESSFUL;
488  }
489
490  /* Check parameter */
491  if (format == NULL || pt == NULL) {
492    return RTEMS_INVALID_ADDRESS;
493  }
494
495  /* Get disk data */
496  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
497  if (sc != RTEMS_SUCCESSFUL) {
498    return sc;
499  }
500
501  /* Align end of disk on cylinder boundary if necessary */
502  if (dos_compatibility) {
503    disk_end -= (disk_end % record_space);
504  }
505
506  /* Check that we have a consistent partition table */
507  for (i = 0; i < count; ++i) {
508    const rtems_bdpart_partition *p = pt + i;
509
510    /* Check that begin and end are proper within the disk */
511    if (p->begin >= disk_end || p->end > disk_end) {
512      esc = RTEMS_INVALID_NUMBER;
513      goto cleanup;
514    }
515
516    /* Check that begin and end are valid */
517    if (p->begin >= p->end) {
518      esc = RTEMS_INVALID_NUMBER;
519      goto cleanup;
520    }
521
522    /* Check that partitions do not overlap */
523    if (i > 0 && pt [i - 1].end > p->begin) {
524      esc = RTEMS_INVALID_NUMBER;
525      goto cleanup;
526    }
527  }
528
529  /* Check format */
530  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
531    esc = RTEMS_NOT_IMPLEMENTED;
532    goto cleanup;
533  }
534
535  /*
536   * Set primary partition count.  If we have more than four partitions we need
537   * an extended partition which will contain the partitions of number four and
538   * above as logical partitions.  If we have four or less partitions we can
539   * use the primary partition table.
540   */
541  ppc = count <= 4 ? count : 3;
542
543  /*
544   * Check that the first primary partition starts at head one and sector one
545   * under the virtual one head and 63 sectors geometry if necessary.
546   */
547  if (dos_compatibility && pt [0].begin != RTEMS_BDPART_MBR_CYLINDER_SIZE) {
548    esc = RTEMS_INVALID_NUMBER;
549    goto cleanup;
550  }
551
552  /*
553   * Check that we have enough space for the EBRs.  The partitions with number
554   * four and above are logical partitions if we have more than four partitions
555   * in total.  The logical partitions are contained in the extended partition.
556   * Each logical partition is described via one EBR preceding the partition.
557   * The space for the EBR and maybe some space which is needed for DOS
558   * compatibility resides between the partitions.  So there have to be gaps of
559   * the appropriate size between the partitions.
560   */
561  for (i = ppc; i < count; ++i) {
562    if ((pt [i].begin - pt [i - 1].end) < record_space) {
563      esc = RTEMS_INVALID_NUMBER;
564      goto cleanup;
565    }
566  }
567
568  /* Check that we can convert the parition descriptions to the MBR format */
569  for (i = 0; i < count; ++i) {
570    uint8_t type = 0;
571
572    const rtems_bdpart_partition *p = pt + i;
573
574    /* Check type */
575    if (!rtems_bdpart_to_mbr_partition_type( p->type, &type)) {
576      esc =  RTEMS_INVALID_ID;
577      goto cleanup;
578    }
579
580    /* Check flags */
581    if (p->flags > 0xffU) {
582      esc = RTEMS_INVALID_ID;
583      goto cleanup;
584    }
585
586    /* Check ID */
587    /* TODO */
588  }
589
590  /* New MBR */
591  sc = rtems_bdpart_new_record( disk, 0, &block);
592  if (sc != RTEMS_SUCCESSFUL) {
593    esc = sc;
594    goto cleanup;
595  }
596
597  /* Write disk ID */
598  rtems_uint32_to_little_endian(
599    format->mbr.disk_id,
600    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
601  );
602
603  /* Write primary partition table */
604  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
605  for (i = 0; i < ppc; ++i) {
606    const rtems_bdpart_partition *p = pt + i;
607
608    /* Write partition entry */
609    rtems_bdpart_write_mbr_partition(
610      data,
611      p->begin,
612      p->end - p->begin,
613      rtems_bdpart_mbr_partition_type( p->type),
614      (uint8_t) p->flags
615    );
616
617    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
618  }
619
620  /* Write extended partition with logical partitions if necessary */
621  if (ppc != count) {
622    rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
623
624    /* Begin of extended partition */
625    rtems_blkdev_bnum ep_begin = pt [ppc].begin - record_space;
626
627    /* Write extended partition */
628    rtems_bdpart_write_mbr_partition(
629      data,
630      ep_begin,
631      disk_end - ep_begin,
632      RTEMS_BDPART_MBR_EXTENDED,
633      0
634    );
635
636    /* Write logical partitions */
637    for (i = ppc; i < count; ++i) {
638      const rtems_bdpart_partition *p = pt + i;
639
640      /* Write second partition entry */
641      if (i > ppc) {
642        rtems_blkdev_bnum begin = p->begin - record_space;
643
644        rtems_bdpart_write_mbr_partition(
645          block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1,
646          begin - ep_begin,
647          disk_end - begin,
648          RTEMS_BDPART_MBR_EXTENDED,
649          0
650        );
651      }
652
653      /* New EBR */
654      ebr = p->begin - record_space;
655      sc = rtems_bdpart_new_record( disk, ebr, &block);
656      if (sc != RTEMS_SUCCESSFUL) {
657        esc = sc;
658        goto cleanup;
659      }
660
661      /* Write first partition entry */
662      rtems_bdpart_write_mbr_partition(
663        block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
664        record_space,
665        p->end - p->begin,
666        rtems_bdpart_mbr_partition_type( p->type),
667        (uint8_t) p->flags
668      );
669    }
670  }
671
672cleanup:
673
674  if (block != NULL) {
675    rtems_bdbuf_sync( block);
676  }
677
678  return esc;
679}
680
681rtems_status_code rtems_bdpart_create(
682  const char *disk_name,
683  const rtems_bdpart_format *format,
684  rtems_bdpart_partition *pt,
685  const unsigned *dist,
686  size_t count
687)
688{
689  rtems_status_code sc = RTEMS_SUCCESSFUL;
690  bool dos_compatibility = format != NULL
691    && format->type == RTEMS_BDPART_FORMAT_MBR
692    && format->mbr.dos_compatibility;
693  rtems_blkdev_bnum disk_end = 0;
694  rtems_blkdev_bnum pos = 0;
695  rtems_blkdev_bnum dist_sum = 0;
696  rtems_blkdev_bnum record_space =
697    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
698  rtems_blkdev_bnum overhead = 0;
699  rtems_blkdev_bnum free_space = 0;
700  dev_t disk = 0;
701  size_t i = 0;
702
703  /* Check if we have something to do */
704  if (count == 0) {
705    /* Nothing to do */
706    return RTEMS_SUCCESSFUL;
707  }
708
709  /* Check parameter */
710  if (format == NULL || pt == NULL || dist == NULL) {
711    return RTEMS_INVALID_ADDRESS;
712  }
713
714  /* Get disk data */
715  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
716  if (sc != RTEMS_SUCCESSFUL) {
717    return sc;
718  }
719
720  /* Get distribution sum and check for overflow */
721  for (i = 0; i < count; ++i) {
722    unsigned prev_sum = dist_sum;
723
724    dist_sum += dist [i];
725
726    if (dist_sum < prev_sum) {
727      return RTEMS_INVALID_NUMBER;
728    }
729
730    if (dist [i] == 0) {
731      return RTEMS_INVALID_NUMBER;
732    }
733  }
734
735  /* Check format */
736  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
737    return RTEMS_NOT_IMPLEMENTED;
738  }
739
740  /* Align end of disk on cylinder boundary if necessary */
741  if (dos_compatibility) {
742    disk_end -= (disk_end % record_space);
743  }
744
745  /*
746   * We need at least space for the MBR and the compatibility space for the
747   * first primary partition.
748   */
749  overhead += record_space;
750
751  /*
752   * In case we need an extended partition and logical partitions we have to
753   * account for the space of each EBR.
754   */
755  if (count > 4) {
756    overhead += (count - 3) * record_space;
757  }
758
759  /*
760   * Account space to align every partition on cylinder boundaries if
761   * necessary.
762   */
763  if (dos_compatibility) {
764    overhead += (count - 1) * record_space;
765  }
766
767  /* Check disk space */
768  if ((overhead + count) > disk_end) {
769    return RTEMS_IO_ERROR;
770  }
771
772  /* Begin of first primary partition */
773  pos = record_space;
774
775  /* Space for partitions */
776  free_space = disk_end - overhead;
777
778  for (i = 0; i < count; ++i) {
779    rtems_bdpart_partition *p = pt + i;
780
781    /* Partition size */
782    rtems_blkdev_bnum s = free_space * dist [i];
783    if (s < free_space || s < dist [i]) {
784      /* TODO: Calculate without overflow */
785      return RTEMS_INVALID_NUMBER;
786    }
787    s /= dist_sum;
788
789    /* Ensure that the partition is not empty */
790    if (s == 0) {
791      s = 1;
792    }
793
794    /* Align partition upwards */
795    s += record_space - (s % record_space);
796
797    /* Partition begin and end */
798    p->begin = pos;
799    pos += s;
800    p->end = pos;
801
802    /* Reserve space for the EBR if necessary */
803    if (count > 4 && i > 2) {
804      p->begin += record_space;
805    }
806  }
807
808  /* Expand the last partition to the disk end */
809  pt [count - 1].end = disk_end;
810
811  return RTEMS_SUCCESSFUL;
812}
813
814#define RTEMS_BDPART_NUMBER_SIZE 4
815
816rtems_status_code rtems_bdpart_register(
817  const char *disk_name,
818  const rtems_bdpart_partition *pt,
819  size_t count
820)
821{
822  rtems_status_code sc = RTEMS_SUCCESSFUL;
823  rtems_status_code esc = RTEMS_SUCCESSFUL;
824  rtems_device_major_number major = 0;
825  rtems_device_minor_number minor = 0;
826  rtems_blkdev_bnum disk_end = 0;
827  dev_t disk = 0;
828  dev_t logical_disk = 0;
829  char *logical_disk_name = NULL;
830  char *logical_disk_marker = NULL;
831  size_t disk_name_size = strlen( disk_name);
832  size_t i = 0;
833
834  /* Get disk data */
835  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
836  if (sc != RTEMS_SUCCESSFUL) {
837    return sc;
838  }
839
840  /* Get the disk device identifier */
841  rtems_filesystem_split_dev_t( disk, major, minor);
842
843  /* Create logical disk name */
844  logical_disk_name = malloc( disk_name_size + RTEMS_BDPART_NUMBER_SIZE);
845  if (logical_disk_name == NULL) {
846    return RTEMS_NO_MEMORY;
847  }
848  strncpy( logical_disk_name, disk_name, disk_name_size);
849  logical_disk_marker = logical_disk_name + disk_name_size;
850
851  /* Create a logical disk for each partition */
852  for (i = 0; i < count; ++i) {
853    const rtems_bdpart_partition *p = pt + i;
854    int rv = 0;
855
856    /* New minor number */
857    ++minor;
858
859    /* Create a new device identifier */
860    logical_disk = rtems_filesystem_make_dev_t( major, minor);
861
862    /* Set partition number for logical disk name */
863    rv = snprintf( logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
864    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
865      esc = RTEMS_INVALID_NAME;
866      goto cleanup;
867    }
868
869    /* Create logical disk */
870    sc = rtems_disk_create_log(
871      logical_disk,
872      disk,
873      p->begin,
874      p->end - p->begin,
875      logical_disk_name
876    );
877    if (sc != RTEMS_SUCCESSFUL) {
878      esc = sc;
879      goto cleanup;
880    }
881  }
882
883cleanup:
884
885  free( logical_disk_name);
886
887  return esc;
888}
889
890rtems_status_code rtems_bdpart_register_from_disk( const char *disk_name)
891{
892  rtems_status_code sc = RTEMS_SUCCESSFUL;
893  rtems_bdpart_format format;
894  rtems_bdpart_partition pt [RTEMS_BDPART_PARTITION_NUMBER_HINT];
895  size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT;
896
897  /* Read partitions */
898  sc = rtems_bdpart_read( disk_name, &format, pt, &count);
899  if (sc != RTEMS_SUCCESSFUL) {
900    return sc;
901  }
902
903  /* Register partitions */
904  return rtems_bdpart_register( disk_name, pt, count);
905}
906
907rtems_status_code rtems_bdpart_unregister(
908  const char *disk_name,
909  const rtems_bdpart_partition *pt __attribute__((unused)),
910  size_t count
911)
912{
913  rtems_status_code sc = RTEMS_SUCCESSFUL;
914  rtems_device_major_number major = 0;
915  rtems_device_minor_number minor = 0;
916  rtems_blkdev_bnum disk_end = 0;
917  dev_t disk = 0;
918  dev_t logical_disk = 0;
919  size_t i = 0;
920
921  /* Get disk data */
922  sc = rtems_bdpart_get_disk_data( disk_name, &disk, &disk_end);
923  if (sc != RTEMS_SUCCESSFUL) {
924    return sc;
925  }
926
927  /* Get the disk device identifier */
928  rtems_filesystem_split_dev_t( disk, major, minor);
929
930  /* Create a logical disk for each partition */
931  for (i = 0; i < count; ++i) {
932    /* New minor number */
933    ++minor;
934
935    /* Get the device identifier */
936    logical_disk = rtems_filesystem_make_dev_t( major, minor);
937
938    /* Delete logical disk */
939    sc = rtems_disk_delete( logical_disk);
940    if (sc != RTEMS_SUCCESSFUL) {
941      return sc;
942    }
943  }
944
945  return RTEMS_SUCCESSFUL;
946}
947
948rtems_status_code rtems_bdpart_mount(
949  const char *disk_name,
950  const rtems_bdpart_partition *pt __attribute__((unused)),
951  size_t count,
952  const char *mount_base
953)
954{
955  rtems_status_code esc = RTEMS_SUCCESSFUL;
956  const char *disk_file_name = strrchr( disk_name, '/');
957  char *logical_disk_name = NULL;
958  char *logical_disk_marker = NULL;
959  char *mount_point = NULL;
960  char *mount_marker = NULL;
961  size_t disk_file_name_size = 0;
962  size_t disk_name_size = strlen( disk_name);
963  size_t mount_base_size = strlen( mount_base);
964  size_t i = 0;
965
966  /* Create logical disk name base */
967  logical_disk_name = malloc( disk_name_size + RTEMS_BDPART_NUMBER_SIZE);
968  if (logical_disk_name == NULL) {
969    return RTEMS_NO_MEMORY;
970  }
971  strncpy( logical_disk_name, disk_name, disk_name_size);
972
973  /* Get disk file name */
974  if (disk_file_name != NULL) {
975    disk_file_name += 1;
976    disk_file_name_size = strlen( disk_file_name);
977  } else {
978    disk_file_name = disk_name;
979    disk_file_name_size = disk_name_size;
980  }
981
982  /* Create mount point base */
983  mount_point = malloc( mount_base_size + 1 + disk_file_name_size + RTEMS_BDPART_NUMBER_SIZE);
984  if (mount_point == NULL) {
985    esc = RTEMS_NO_MEMORY;
986    goto cleanup;
987  }
988  strncpy( mount_point, mount_base, mount_base_size);
989  mount_point [mount_base_size] = '/';
990  strncpy( mount_point + mount_base_size + 1, disk_file_name, disk_file_name_size);
991
992  /* Markers */
993  logical_disk_marker = logical_disk_name + disk_name_size;
994  mount_marker = mount_point + mount_base_size + 1 + disk_file_name_size;
995
996  /* Mount supported file systems for each partition */
997  for (i = 0; i < count; ++i) {
998    /* Create logical disk name */
999    int rv = snprintf( logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
1000    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
1001      esc = RTEMS_INVALID_NAME;
1002      goto cleanup;
1003    }
1004
1005    /* Create mount point */
1006    strncpy( mount_marker, logical_disk_marker, RTEMS_BDPART_NUMBER_SIZE);
1007    rv = rtems_fsmount_create_mount_point( mount_point);
1008    if (rv != 0) {
1009      esc = RTEMS_IO_ERROR;
1010      goto cleanup;
1011    }
1012
1013    /* Mount */
1014    rv = mount(
1015      NULL,
1016      &msdos_ops,
1017      0,
1018      logical_disk_name,
1019      mount_point
1020    );
1021    if (rv != 0) {
1022      rmdir( mount_point);
1023    }
1024  }
1025
1026cleanup:
1027
1028  free( logical_disk_name);
1029  free( mount_point);
1030
1031  return esc;
1032}
1033
1034rtems_status_code rtems_bdpart_unmount(
1035  const char *disk_name,
1036  const rtems_bdpart_partition *pt __attribute__((unused)),
1037  size_t count,
1038  const char *mount_base
1039)
1040{
1041  rtems_status_code esc = RTEMS_SUCCESSFUL;
1042  const char *disk_file_name = strrchr( disk_name, '/');
1043  char *mount_point = NULL;
1044  char *mount_marker = NULL;
1045  size_t disk_file_name_size = 0;
1046  size_t disk_name_size = strlen( disk_name);
1047  size_t mount_base_size = strlen( mount_base);
1048  size_t i = 0;
1049
1050  /* Get disk file name */
1051  if (disk_file_name != NULL) {
1052    disk_file_name += 1;
1053    disk_file_name_size = strlen( disk_file_name);
1054  } else {
1055    disk_file_name = disk_name;
1056    disk_file_name_size = disk_name_size;
1057  }
1058
1059  /* Create mount point base */
1060  mount_point = malloc( mount_base_size + 1 + disk_file_name_size + RTEMS_BDPART_NUMBER_SIZE);
1061  if (mount_point == NULL) {
1062    esc = RTEMS_NO_MEMORY;
1063    goto cleanup;
1064  }
1065  strncpy( mount_point, mount_base, mount_base_size);
1066  mount_point [mount_base_size] = '/';
1067  strncpy( mount_point + mount_base_size + 1, disk_file_name, disk_file_name_size);
1068
1069  /* Marker */
1070  mount_marker = mount_point + mount_base_size + 1 + disk_file_name_size;
1071
1072  /* Mount supported file systems for each partition */
1073  for (i = 0; i < count; ++i) {
1074    /* Create mount point */
1075    int rv = snprintf( mount_marker, RTEMS_BDPART_NUMBER_SIZE, "%zu", i + 1);
1076    if (rv >= RTEMS_BDPART_NUMBER_SIZE) {
1077      esc = RTEMS_INVALID_NAME;
1078      goto cleanup;
1079    }
1080
1081    /* Unmount */
1082    rv = unmount( mount_point);
1083    if (rv == 0) {
1084      /* Remove mount point */
1085      rv = rmdir( mount_point);
1086      if (rv != 0) {
1087        esc = RTEMS_IO_ERROR;
1088        goto cleanup;
1089      }
1090    }
1091  }
1092
1093cleanup:
1094
1095  free( mount_point);
1096
1097  return esc;
1098}
1099
1100void rtems_bdpart_dump( const rtems_bdpart_partition *pt, size_t count)
1101{
1102  size_t i = 0;
1103
1104  printf(
1105    "-------------------------------------------------------------------------------\n"
1106    "                                PARTITION TABLE\n"
1107    "------------+------------+-----------------------------------------------------\n"
1108    " BEGIN      | END        | TYPE\n"
1109    "------------+------------+-----------------------------------------------------\n"
1110  );
1111
1112  for (i = 0; i < count; ++i) {
1113    const rtems_bdpart_partition *p = pt + i;
1114    const char *type = NULL;
1115    char type_buffer [52];
1116    uint8_t type_mbr = 0;
1117
1118    if (rtems_bdpart_to_mbr_partition_type( p->type, &type_mbr)) {
1119      switch (type_mbr) {
1120        case RTEMS_BDPART_MBR_FAT_12:
1121          type = "FAT 12";
1122          break;
1123        case RTEMS_BDPART_MBR_FAT_16:
1124          type = "FAT 16";
1125          break;
1126        case RTEMS_BDPART_MBR_FAT_16_LBA:
1127          type = "FAT 16 LBA";
1128          break;
1129        case RTEMS_BDPART_MBR_FAT_32:
1130          type = "FAT 32";
1131          break;
1132        case RTEMS_BDPART_MBR_FAT_32_LBA:
1133          type = "FAT 32 LBA";
1134          break;
1135        case RTEMS_BDPART_MBR_DATA:
1136          type = "DATA";
1137          break;
1138        default:
1139          snprintf( type_buffer, sizeof( type_buffer), "0x%02" PRIx8, type_mbr);
1140          type = type_buffer;
1141          break;
1142      }
1143    } else {
1144      rtems_bdpart_type_to_string( p->type, type_buffer);
1145      type = type_buffer;
1146    }
1147
1148    printf(
1149      " %10lu | %10lu |%52s\n",
1150      (unsigned long) p->begin,
1151      (unsigned long) p->end,
1152      type
1153    );
1154  }
1155
1156  puts( "------------+------------+-----------------------------------------------------");
1157}
Note: See TracBrowser for help on using the repository browser.