source: rtems/cpukit/libblock/src/bdpart-write.c @ 9de9b7d2

4.115
Last change on this file since 9de9b7d2 was f6c7bcfe, checked in by Mathew Kallada <matkallada@…>, on 12/21/12 at 17:42:39

libblock: Doxygen Enhancement Task #1

  • Property mode set to 100644
File size: 7.6 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 <string.h>
26
27#include <rtems.h>
28#include <rtems/bdbuf.h>
29#include <rtems/bdpart.h>
30#include <rtems/endian.h>
31
32static void rtems_bdpart_write_mbr_partition(
33  uint8_t *data,
34  uint32_t begin,
35  uint32_t size,
36  uint8_t type,
37  uint8_t flags
38)
39{
40  rtems_uint32_to_little_endian( begin, data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
41  rtems_uint32_to_little_endian( size, data + RTEMS_BDPART_MBR_OFFSET_SIZE);
42  data [RTEMS_BDPART_MBR_OFFSET_TYPE] = type;
43  data [RTEMS_BDPART_MBR_OFFSET_FLAGS] = flags;
44}
45
46static rtems_status_code rtems_bdpart_new_record(
47  rtems_disk_device *dd,
48  rtems_blkdev_bnum index,
49  rtems_bdbuf_buffer **block
50)
51{
52  rtems_status_code sc = RTEMS_SUCCESSFUL;
53
54  /* Synchronize previous block if necessary */
55  if (*block != NULL) {
56    sc = rtems_bdbuf_sync( *block);
57    if (sc != RTEMS_SUCCESSFUL) {
58      return sc;
59    }
60  }
61
62  /* Read the new record block (this accounts for disk block sizes > 512) */
63  sc = rtems_bdbuf_read( dd, index, block);
64  if (sc != RTEMS_SUCCESSFUL) {
65    return sc;
66  }
67
68  /* just in case block did not get filled in */
69  if ( *block == NULL ) {
70    return RTEMS_INVALID_ADDRESS;
71  }
72
73  /* Clear record */
74  memset( (*block)->buffer, 0, RTEMS_BDPART_BLOCK_SIZE);
75
76  /* Write signature */
77  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0] =
78    RTEMS_BDPART_MBR_SIGNATURE_0;
79  (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1] =
80    RTEMS_BDPART_MBR_SIGNATURE_1;
81
82  return RTEMS_SUCCESSFUL;
83}
84
85rtems_status_code rtems_bdpart_write(
86  const char *disk_name,
87  const rtems_bdpart_format *format,
88  const rtems_bdpart_partition *pt,
89  size_t count
90)
91{
92  rtems_status_code sc = RTEMS_SUCCESSFUL;
93  rtems_status_code esc = RTEMS_SUCCESSFUL;
94  bool dos_compatibility = format != NULL
95    && format->type == RTEMS_BDPART_FORMAT_MBR
96    && format->mbr.dos_compatibility;
97  rtems_bdbuf_buffer *block = NULL;
98  rtems_blkdev_bnum disk_end = 0;
99  rtems_blkdev_bnum record_space =
100    dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
101  size_t ppc = 0; /* Primary partition count */
102  size_t i = 0;
103  uint8_t *data = NULL;
104  int fd = -1;
105  rtems_disk_device *dd = NULL;
106
107  /* Check if we have something to do */
108  if (count == 0) {
109    /* Nothing to do */
110    return RTEMS_SUCCESSFUL;
111  }
112
113  /* Check parameter */
114  if (format == NULL || pt == NULL) {
115    return RTEMS_INVALID_ADDRESS;
116  }
117
118  /* Get disk data */
119  sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
120  if (sc != RTEMS_SUCCESSFUL) {
121    return sc;
122  }
123
124  /* Align end of disk on cylinder boundary if necessary */
125  if (dos_compatibility) {
126    disk_end -= (disk_end % record_space);
127  }
128
129  /* Check that we have a consistent partition table */
130  for (i = 0; i < count; ++i) {
131    const rtems_bdpart_partition *p = pt + i;
132
133    /* Check that begin and end are proper within the disk */
134    if (p->begin >= disk_end || p->end > disk_end) {
135      esc = RTEMS_INVALID_NUMBER;
136      goto cleanup;
137    }
138
139    /* Check that begin and end are valid */
140    if (p->begin >= p->end) {
141      esc = RTEMS_INVALID_NUMBER;
142      goto cleanup;
143    }
144
145    /* Check that partitions do not overlap */
146    if (i > 0 && pt [i - 1].end > p->begin) {
147      esc = RTEMS_INVALID_NUMBER;
148      goto cleanup;
149    }
150  }
151
152  /* Check format */
153  if (format->type != RTEMS_BDPART_FORMAT_MBR) {
154    esc = RTEMS_NOT_IMPLEMENTED;
155    goto cleanup;
156  }
157
158  /*
159   * Set primary partition count.  If we have more than four partitions we need
160   * an extended partition which will contain the partitions of number four and
161   * above as logical partitions.  If we have four or less partitions we can
162   * use the primary partition table.
163   */
164  ppc = count <= 4 ? count : 3;
165
166  /*
167   * Check that the first primary partition starts at head one and sector one
168   * under the virtual one head and 63 sectors geometry if necessary.
169   */
170  if (dos_compatibility && pt [0].begin != RTEMS_BDPART_MBR_CYLINDER_SIZE) {
171    esc = RTEMS_INVALID_NUMBER;
172    goto cleanup;
173  }
174
175  /*
176   * Check that we have enough space for the EBRs.  The partitions with number
177   * four and above are logical partitions if we have more than four partitions
178   * in total.  The logical partitions are contained in the extended partition.
179   * Each logical partition is described via one EBR preceding the partition.
180   * The space for the EBR and maybe some space which is needed for DOS
181   * compatibility resides between the partitions.  So there have to be gaps of
182   * the appropriate size between the partitions.
183   */
184  for (i = ppc; i < count; ++i) {
185    if ((pt [i].begin - pt [i - 1].end) < record_space) {
186      esc = RTEMS_INVALID_NUMBER;
187      goto cleanup;
188    }
189  }
190
191  /* Check that we can convert the parition descriptions to the MBR format */
192  for (i = 0; i < count; ++i) {
193    uint8_t type = 0;
194
195    const rtems_bdpart_partition *p = pt + i;
196
197    /* Check type */
198    if (!rtems_bdpart_to_mbr_partition_type( p->type, &type)) {
199      esc =  RTEMS_INVALID_ID;
200      goto cleanup;
201    }
202
203    /* Check flags */
204    if (p->flags > 0xffU) {
205      esc = RTEMS_INVALID_ID;
206      goto cleanup;
207    }
208
209    /* Check ID */
210    /* TODO */
211  }
212
213  /* New MBR */
214  sc = rtems_bdpart_new_record( dd, 0, &block);
215  if (sc != RTEMS_SUCCESSFUL) {
216    esc = sc;
217    goto cleanup;
218  }
219
220  /* Write disk ID */
221  rtems_uint32_to_little_endian(
222    format->mbr.disk_id,
223    block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
224  );
225
226  /* Write primary partition table */
227  data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
228  for (i = 0; i < ppc; ++i) {
229    const rtems_bdpart_partition *p = pt + i;
230
231    /* Write partition entry */
232    rtems_bdpart_write_mbr_partition(
233      data,
234      p->begin,
235      p->end - p->begin,
236      rtems_bdpart_mbr_partition_type( p->type),
237      (uint8_t) p->flags
238    );
239
240    data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
241  }
242
243  /* Write extended partition with logical partitions if necessary */
244  if (ppc != count) {
245    rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
246
247    /* Begin of extended partition */
248    rtems_blkdev_bnum ep_begin = pt [ppc].begin - record_space;
249
250    /* Write extended partition */
251    rtems_bdpart_write_mbr_partition(
252      data,
253      ep_begin,
254      disk_end - ep_begin,
255      RTEMS_BDPART_MBR_EXTENDED,
256      0
257    );
258
259    /* Write logical partitions */
260    for (i = ppc; i < count; ++i) {
261      const rtems_bdpart_partition *p = pt + i;
262
263      /* Write second partition entry */
264      if (i > ppc) {
265        rtems_blkdev_bnum begin = p->begin - record_space;
266
267        rtems_bdpart_write_mbr_partition(
268          block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1,
269          begin - ep_begin,
270          disk_end - begin,
271          RTEMS_BDPART_MBR_EXTENDED,
272          0
273        );
274      }
275
276      /* New EBR */
277      ebr = p->begin - record_space;
278      sc = rtems_bdpart_new_record( dd, ebr, &block);
279      if (sc != RTEMS_SUCCESSFUL) {
280        esc = sc;
281        goto cleanup;
282      }
283
284      /* Write first partition entry */
285      rtems_bdpart_write_mbr_partition(
286        block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
287        record_space,
288        p->end - p->begin,
289        rtems_bdpart_mbr_partition_type( p->type),
290        (uint8_t) p->flags
291      );
292    }
293  }
294
295cleanup:
296
297  if (fd >= 0) {
298    close( fd);
299  }
300
301  if (block != NULL) {
302    rtems_bdbuf_sync( block);
303  }
304
305  return esc;
306}
Note: See TracBrowser for help on using the repository browser.