source: rtems/cpukit/libblock/src/bdpart.c @ 04fee31

4.104.11
Last change on this file since 04fee31 was 04fee31, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 20, 2010 at 5:10:36 PM

2010-01-20 Joel Sherrill <joel.sherrill@…>

Coverity Id 7
Coverity Id 8

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