source: rtems/cpukit/libblock/src/bdpart.c @ 834df50

4.104.115
Last change on this file since 834df50 was 834df50, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 05/05/09 at 12:53:41

New files

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