source: rtems/cpukit/libblock/src/bdpart-read.c @ 3d60c1b

4.115
Last change on this file since 3d60c1b was 796967c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 16:19:49

libblock: Change bdbuf API

The functions

o rtems_bdbuf_get(),
o rtems_bdbuf_read(),
o rtems_bdbuf_syncdev(), and
o rtems_bdbuf_purge_dev(),

use now the disk device instead of the device identifier. This makes
bdbuf independent of rtems_disk_obtain() and rtems_disk_release(). It
is the responsiblity of the file system to obtain the disk device. This
also reduces the overhead to get a buffer.

The key for the AVL tree uses now the disk device instead of the device
identifier. The pointer is interpreted as an unsigned integer. This
reduces the memory overhead and makes the comparison operation a bit
faster.

Removed function rtems_bdbuf_purge_major(). This function was too
destructive and could have unpredictable side effects.

  • 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  const 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  const 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  const 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  const 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.