source: rtems/cpukit/libblock/src/bdpart-read.c @ 40284de

4.115
Last change on this file since 40284de was 40284de, checked in by Sebastian Huber <sebastian.huber@…>, on 05/30/12 at 10:43:56

libblock: Remove const qualifier from bdbuf API

This allows addtion of per disk statistics for example.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bdpart
5 *
6 * Block device partition management.
7 */
8
9/*
10 * Copyright (c) 2009, 2010
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <sys/stat.h>
27#include <fcntl.h>
28
29#include <rtems.h>
30#include <rtems/bdbuf.h>
31#include <rtems/bdpart.h>
32#include <rtems/endian.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
42static const uuid_t RTEMS_BDPART_MBR_MASTER_TYPE =
43  RTEMS_BDPART_MBR_PARTITION_TYPE( RTEMS_BDPART_MBR_EMPTY);
44
45void rtems_bdpart_to_partition_type( uint8_t mbr_type, uuid_t type)
46{
47  type [0] = mbr_type;
48  memcpy( type + 1, RTEMS_BDPART_MBR_MASTER_TYPE + 1, sizeof( uuid_t) - 1);
49}
50
51bool rtems_bdpart_to_mbr_partition_type(
52  const uuid_t type,
53  uint8_t *mbr_type
54)
55{
56  *mbr_type = rtems_bdpart_mbr_partition_type( type);
57
58  return memcmp(
59    type + 1,
60    RTEMS_BDPART_MBR_MASTER_TYPE + 1,
61    sizeof( uuid_t) - 1
62  ) == 0;
63}
64
65/*
66 * FIXME: This code should the deviceio interface and not the bdbug interface.
67 */
68rtems_status_code rtems_bdpart_get_disk_data(
69  const char *disk_name,
70  int *fd_ptr,
71  rtems_disk_device **dd_ptr,
72  rtems_blkdev_bnum *disk_end
73)
74{
75  rtems_status_code sc = RTEMS_SUCCESSFUL;
76  int rv = 0;
77  int fd = -1;
78  rtems_disk_device *dd = NULL;
79  rtems_blkdev_bnum disk_begin = 0;
80  rtems_blkdev_bnum block_size = 0;
81
82  /* Open device file */
83  fd = open( disk_name, O_RDWR);
84  if (fd < 0) {
85    sc = RTEMS_INVALID_NAME;
86    goto error;
87  }
88
89  /* Get disk handle */
90  rv = rtems_disk_fd_get_disk_device( fd, &dd);
91  if (rv != 0) {
92    sc = RTEMS_INVALID_NAME;
93    goto error;
94  }
95
96  /* Get disk begin, end and block size */
97  disk_begin = dd->start;
98  *disk_end = dd->size;
99  block_size = dd->block_size;
100
101  /* Check block size */
102  if (block_size < RTEMS_BDPART_BLOCK_SIZE) {
103    sc = RTEMS_IO_ERROR;
104    goto error;
105  }
106
107  /* Check that we have do not have a logical disk */
108  if (disk_begin != 0) {
109    sc = RTEMS_IO_ERROR;
110    goto error;
111  }
112
113error:
114
115  if (sc == RTEMS_SUCCESSFUL && fd_ptr != NULL && dd_ptr != NULL) {
116    *fd_ptr = fd;
117    *dd_ptr = dd;
118  } else {
119    close( fd);
120  }
121
122  return sc;
123}
124
125static bool rtems_bdpart_is_valid_record( const uint8_t *data)
126{
127  return data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0]
128      == RTEMS_BDPART_MBR_SIGNATURE_0
129    && data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1]
130      == RTEMS_BDPART_MBR_SIGNATURE_1;
131}
132
133static rtems_blkdev_bnum rtems_bdpart_next_ebr( const uint8_t *data)
134{
135  rtems_blkdev_bnum begin =
136    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
137  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
138
139  if (type == RTEMS_BDPART_MBR_EXTENDED) {
140    return begin;
141  } else {
142    return 0;
143  }
144}
145
146static rtems_status_code rtems_bdpart_read_mbr_partition(
147  const uint8_t *data,
148  rtems_bdpart_partition **p,
149  const rtems_bdpart_partition *p_end,
150  rtems_blkdev_bnum *ep_begin
151)
152{
153  rtems_blkdev_bnum begin =
154    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
155  rtems_blkdev_bnum size =
156    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_SIZE);
157  rtems_blkdev_bnum end = begin + size;
158  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
159
160  if (type == RTEMS_BDPART_MBR_EMPTY) {
161    return RTEMS_SUCCESSFUL;
162  } else if (*p == p_end) {
163    return RTEMS_TOO_MANY;
164  } else if (begin >= end) {
165    return RTEMS_IO_ERROR;
166  } else if (type == RTEMS_BDPART_MBR_EXTENDED) {
167    if (ep_begin != NULL) {
168      *ep_begin = begin;
169    }
170  } else {
171    /* Increment partition index */
172    ++(*p);
173
174    /* Clear partition */
175    memset( *p, 0, sizeof( rtems_bdpart_partition));
176
177    /* Set values */
178    (*p)->begin = begin;
179    (*p)->end = end;
180    rtems_bdpart_to_partition_type( type, (*p)->type);
181    (*p)->flags = data [RTEMS_BDPART_MBR_OFFSET_FLAGS];
182  }
183
184  return RTEMS_SUCCESSFUL;
185}
186
187static rtems_status_code rtems_bdpart_read_record(
188  rtems_disk_device *dd,
189  rtems_blkdev_bnum index,
190  rtems_bdbuf_buffer **block
191)
192{
193  rtems_status_code sc = RTEMS_SUCCESSFUL;
194
195  /* Release previous block if necessary */
196  if (*block != NULL) {
197    sc = rtems_bdbuf_release( *block);
198    if (sc != RTEMS_SUCCESSFUL) {
199      return sc;
200    }
201  }
202
203  /* Read the record block */
204  sc = rtems_bdbuf_read( dd, index, block);
205  if (sc != RTEMS_SUCCESSFUL) {
206    return sc;
207  }
208
209  /* just in case block did not get filled in */
210  if ( *block == NULL ) {
211    return RTEMS_INVALID_ADDRESS;
212  }
213
214  /* Check MBR signature */
215  if (!rtems_bdpart_is_valid_record( (*block)->buffer)) {
216    return RTEMS_IO_ERROR;
217  }
218
219  return RTEMS_SUCCESSFUL;
220}
221
222rtems_status_code rtems_bdpart_read(
223  const char *disk_name,
224  rtems_bdpart_format *format,
225  rtems_bdpart_partition *pt,
226  size_t *count
227)
228{
229  rtems_status_code sc = RTEMS_SUCCESSFUL;
230  rtems_status_code esc = RTEMS_SUCCESSFUL;
231  rtems_bdbuf_buffer *block = NULL;
232  rtems_bdpart_partition *p = pt - 1;
233  const rtems_bdpart_partition *p_end = pt + (count != NULL ? *count : 0);
234  rtems_blkdev_bnum ep_begin = 0; /* Extended partition begin */
235  rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
236  rtems_blkdev_bnum disk_end = 0;
237  size_t i = 0;
238  const uint8_t *data = NULL;
239  int fd = -1;
240  rtems_disk_device *dd = NULL;
241
242  /* Check parameter */
243  if (format == NULL || pt == NULL || count == NULL) {
244    return RTEMS_INVALID_ADDRESS;
245  }
246
247  /* Set count to a save value */
248  *count = 0;
249
250  /* Get disk data */
251  sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
252  if (sc != RTEMS_SUCCESSFUL) {
253    return sc;
254  }
255
256  /* Read MBR */
257  sc = rtems_bdpart_read_record( dd, 0, &block);
258  if (sc != RTEMS_SUCCESSFUL) {
259    esc = sc;
260    goto cleanup;
261  }
262
263  /* Read the first partition entry */
264  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
265  sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
266  if (sc != RTEMS_SUCCESSFUL) {
267    esc = sc;
268    goto cleanup;
269  }
270
271  /* Determine if we have a MBR or GPT format */
272  if (rtems_bdpart_mbr_partition_type( p->type) == RTEMS_BDPART_MBR_GPT) {
273    esc = RTEMS_NOT_IMPLEMENTED;
274    goto cleanup;
275  }
276
277  /* Set format */
278  format->type = RTEMS_BDPART_FORMAT_MBR;
279  format->mbr.disk_id = rtems_uint32_from_little_endian(
280    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
281  );
282  format->mbr.dos_compatibility = true;
283
284  /* Iterate through the rest of the primary partition table */
285  for (i = 1; i < 4; ++i) {
286    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
287
288    sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
289    if (sc != RTEMS_SUCCESSFUL) {
290      esc = sc;
291      goto cleanup;
292    }
293  }
294
295  /* Iterate through the logical partitions within the extended partition */
296  ebr = ep_begin;
297  while (ebr != 0) {
298    rtems_blkdev_bnum tmp = 0;
299
300    /* Read EBR */
301    sc = rtems_bdpart_read_record( dd, ebr, &block);
302    if (sc != RTEMS_SUCCESSFUL) {
303      esc = sc;
304      goto cleanup;
305    }
306
307    /* Read first partition entry */
308    sc = rtems_bdpart_read_mbr_partition(
309      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
310      &p,
311      p_end,
312      NULL
313    );
314    if (sc != RTEMS_SUCCESSFUL) {
315      esc = sc;
316      goto cleanup;
317    }
318
319    /* Adjust partition begin */
320    tmp = p->begin + ebr;
321    if (tmp > p->begin) {
322      p->begin = tmp;
323    } else {
324      esc = RTEMS_IO_ERROR;
325      goto cleanup;
326    }
327
328    /* Adjust partition end */
329    tmp = p->end + ebr;
330    if (tmp > p->end) {
331      p->end = tmp;
332    } else {
333      esc = RTEMS_IO_ERROR;
334      goto cleanup;
335    }
336
337    /* Read second partition entry for next EBR block */
338    ebr = rtems_bdpart_next_ebr(
339      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1
340    );
341    if (ebr != 0) {
342      /* Adjust partition EBR block index */
343      tmp = ebr + ep_begin;
344      if (tmp > ebr) {
345        ebr = tmp;
346      } else {
347        esc = RTEMS_IO_ERROR;
348        goto cleanup;
349      }
350    }
351  }
352
353  /* Return partition count */
354  *count = (size_t) (p - pt + 1);
355
356cleanup:
357
358  if (fd >= 0) {
359    close( fd);
360  }
361
362  if (block != NULL) {
363    rtems_bdbuf_release( block);
364  }
365
366  return esc;
367}
Note: See TracBrowser for help on using the repository browser.