source: rtems/cpukit/libblock/src/bdpart-read.c @ 121dd881

4.115
Last change on this file since 121dd881 was 121dd881, checked in by Gedare Bloom <gedare@…>, on 09/05/13 at 17:22:49

bdpart: Argument cannot be negative

If open(fd) fails then avoid the error path that calls close(fd).

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2 * @file
3 *
4 * @brief Block Device Partition Management
5 * @ingroup rtems_bdpart
6 */
7
8/*
9 * Copyright (c) 2009, 2010
10 * embedded brains GmbH
11 * Obere Lagerstr. 30
12 * D-82178 Puchheim
13 * Germany
14 * <rtems@embedded-brains.de>
15 *
16 * The license and distribution terms for this file may be
17 * found in the file LICENSE in this distribution or at
18 * http://www.rtems.com/license/LICENSE.
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <string.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;
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 out;
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
122out:
123  return sc;
124}
125
126static bool rtems_bdpart_is_valid_record( const uint8_t *data)
127{
128  return data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0]
129      == RTEMS_BDPART_MBR_SIGNATURE_0
130    && data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1]
131      == RTEMS_BDPART_MBR_SIGNATURE_1;
132}
133
134static rtems_blkdev_bnum rtems_bdpart_next_ebr( const uint8_t *data)
135{
136  rtems_blkdev_bnum begin =
137    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
138  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
139
140  if (type == RTEMS_BDPART_MBR_EXTENDED) {
141    return begin;
142  } else {
143    return 0;
144  }
145}
146
147static rtems_status_code rtems_bdpart_read_mbr_partition(
148  const uint8_t *data,
149  rtems_bdpart_partition **p,
150  const rtems_bdpart_partition *p_end,
151  rtems_blkdev_bnum *ep_begin
152)
153{
154  rtems_blkdev_bnum begin =
155    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
156  rtems_blkdev_bnum size =
157    rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_SIZE);
158  rtems_blkdev_bnum end = begin + size;
159  uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
160
161  if (type == RTEMS_BDPART_MBR_EMPTY) {
162    return RTEMS_SUCCESSFUL;
163  } else if (*p == p_end) {
164    return RTEMS_TOO_MANY;
165  } else if (begin >= end) {
166    return RTEMS_IO_ERROR;
167  } else if (type == RTEMS_BDPART_MBR_EXTENDED) {
168    if (ep_begin != NULL) {
169      *ep_begin = begin;
170    }
171  } else {
172    /* Increment partition index */
173    ++(*p);
174
175    /* Clear partition */
176    memset( *p, 0, sizeof( rtems_bdpart_partition));
177
178    /* Set values */
179    (*p)->begin = begin;
180    (*p)->end = end;
181    rtems_bdpart_to_partition_type( type, (*p)->type);
182    (*p)->flags = data [RTEMS_BDPART_MBR_OFFSET_FLAGS];
183  }
184
185  return RTEMS_SUCCESSFUL;
186}
187
188static rtems_status_code rtems_bdpart_read_record(
189  rtems_disk_device *dd,
190  rtems_blkdev_bnum index,
191  rtems_bdbuf_buffer **block
192)
193{
194  rtems_status_code sc = RTEMS_SUCCESSFUL;
195
196  /* Release previous block if necessary */
197  if (*block != NULL) {
198    sc = rtems_bdbuf_release( *block);
199    if (sc != RTEMS_SUCCESSFUL) {
200      return sc;
201    }
202  }
203
204  /* Read the record block */
205  sc = rtems_bdbuf_read( dd, index, block);
206  if (sc != RTEMS_SUCCESSFUL) {
207    return sc;
208  }
209
210  /* just in case block did not get filled in */
211  if ( *block == NULL ) {
212    return RTEMS_INVALID_ADDRESS;
213  }
214
215  /* Check MBR signature */
216  if (!rtems_bdpart_is_valid_record( (*block)->buffer)) {
217    return RTEMS_IO_ERROR;
218  }
219
220  return RTEMS_SUCCESSFUL;
221}
222
223rtems_status_code rtems_bdpart_read(
224  const char *disk_name,
225  rtems_bdpart_format *format,
226  rtems_bdpart_partition *pt,
227  size_t *count
228)
229{
230  rtems_status_code sc = RTEMS_SUCCESSFUL;
231  rtems_status_code esc = RTEMS_SUCCESSFUL;
232  rtems_bdbuf_buffer *block = NULL;
233  rtems_bdpart_partition *p = pt - 1;
234  const rtems_bdpart_partition *p_end = pt + (count != NULL ? *count : 0);
235  rtems_blkdev_bnum ep_begin = 0; /* Extended partition begin */
236  rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
237  rtems_blkdev_bnum disk_end = 0;
238  size_t i = 0;
239  const uint8_t *data = NULL;
240  int fd = -1;
241  rtems_disk_device *dd = NULL;
242
243  /* Check parameter */
244  if (format == NULL || pt == NULL || count == NULL) {
245    return RTEMS_INVALID_ADDRESS;
246  }
247
248  /* Set count to a save value */
249  *count = 0;
250
251  /* Get disk data */
252  sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
253  if (sc != RTEMS_SUCCESSFUL) {
254    return sc;
255  }
256
257  /* Read MBR */
258  sc = rtems_bdpart_read_record( dd, 0, &block);
259  if (sc != RTEMS_SUCCESSFUL) {
260    esc = sc;
261    goto cleanup;
262  }
263
264  /* Read the first partition entry */
265  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
266  sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
267  if (sc != RTEMS_SUCCESSFUL) {
268    esc = sc;
269    goto cleanup;
270  }
271
272  /* Determine if we have a MBR or GPT format */
273  if (rtems_bdpart_mbr_partition_type( p->type) == RTEMS_BDPART_MBR_GPT) {
274    esc = RTEMS_NOT_IMPLEMENTED;
275    goto cleanup;
276  }
277
278  /* Set format */
279  format->type = RTEMS_BDPART_FORMAT_MBR;
280  format->mbr.disk_id = rtems_uint32_from_little_endian(
281    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
282  );
283  format->mbr.dos_compatibility = true;
284
285  /* Iterate through the rest of the primary partition table */
286  for (i = 1; i < 4; ++i) {
287    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
288
289    sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
290    if (sc != RTEMS_SUCCESSFUL) {
291      esc = sc;
292      goto cleanup;
293    }
294  }
295
296  /* Iterate through the logical partitions within the extended partition */
297  ebr = ep_begin;
298  while (ebr != 0) {
299    rtems_blkdev_bnum tmp = 0;
300
301    /* Read EBR */
302    sc = rtems_bdpart_read_record( dd, ebr, &block);
303    if (sc != RTEMS_SUCCESSFUL) {
304      esc = sc;
305      goto cleanup;
306    }
307
308    /* Read first partition entry */
309    sc = rtems_bdpart_read_mbr_partition(
310      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
311      &p,
312      p_end,
313      NULL
314    );
315    if (sc != RTEMS_SUCCESSFUL) {
316      esc = sc;
317      goto cleanup;
318    }
319
320    /* Adjust partition begin */
321    tmp = p->begin + ebr;
322    if (tmp > p->begin) {
323      p->begin = tmp;
324    } else {
325      esc = RTEMS_IO_ERROR;
326      goto cleanup;
327    }
328
329    /* Adjust partition end */
330    tmp = p->end + ebr;
331    if (tmp > p->end) {
332      p->end = tmp;
333    } else {
334      esc = RTEMS_IO_ERROR;
335      goto cleanup;
336    }
337
338    /* Read second partition entry for next EBR block */
339    ebr = rtems_bdpart_next_ebr(
340      block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1
341    );
342    if (ebr != 0) {
343      /* Adjust partition EBR block index */
344      tmp = ebr + ep_begin;
345      if (tmp > ebr) {
346        ebr = tmp;
347      } else {
348        esc = RTEMS_IO_ERROR;
349        goto cleanup;
350      }
351    }
352  }
353
354  /* Return partition count */
355  *count = (size_t) (p - pt + 1);
356
357cleanup:
358
359  if (fd >= 0) {
360    close( fd);
361  }
362
363  if (block != NULL) {
364    rtems_bdbuf_release( block);
365  }
366
367  return esc;
368}
Note: See TracBrowser for help on using the repository browser.