source: mainline/uspace/lib/label/src/mbr.c@ 99c23405

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 99c23405 was 99c23405, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Persistent partition table modification when creating or deleting partition.

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup liblabel
30 * @{
31 */
32/**
33 * @file Master Boot Record label
34 */
35
36#include <block.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdlib.h>
41
42#include "std/mbr.h"
43#include "mbr.h"
44
45static int mbr_open(service_id_t, label_t **);
46static int mbr_create(service_id_t, label_t **);
47static void mbr_close(label_t *);
48static int mbr_destroy(label_t *);
49static int mbr_get_info(label_t *, label_info_t *);
50static label_part_t *mbr_part_first(label_t *);
51static label_part_t *mbr_part_next(label_part_t *);
52static void mbr_part_get_info(label_part_t *, label_part_info_t *);
53static int mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
54static int mbr_part_destroy(label_part_t *);
55
56static void mbr_unused_pte(mbr_pte_t *);
57static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
58static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
59static int mbr_pte_update(label_t *, mbr_pte_t *, int);
60
61label_ops_t mbr_label_ops = {
62 .open = mbr_open,
63 .create = mbr_create,
64 .close = mbr_close,
65 .destroy = mbr_destroy,
66 .get_info = mbr_get_info,
67 .part_first = mbr_part_first,
68 .part_next = mbr_part_next,
69 .part_get_info = mbr_part_get_info,
70 .part_create = mbr_part_create,
71 .part_destroy = mbr_part_destroy
72};
73
74static int mbr_open(service_id_t sid, label_t **rlabel)
75{
76 label_t *label = NULL;
77 mbr_br_block_t *mbr = NULL;
78 mbr_pte_t *eptr;
79 uint16_t sgn;
80 size_t bsize;
81 aoff64_t nblocks;
82 uint32_t entry;
83 int rc;
84
85 rc = block_get_bsize(sid, &bsize);
86 if (rc != EOK) {
87 rc = EIO;
88 goto error;
89 }
90
91 rc = block_get_nblocks(sid, &nblocks);
92 if (rc != EOK) {
93 rc = EIO;
94 goto error;
95 }
96
97 if (bsize < 512 || (bsize % 512) != 0) {
98 rc = EINVAL;
99 goto error;
100 }
101
102 if (nblocks < mbr_ablock0) {
103 rc = EINVAL;
104 goto error;
105 }
106
107 mbr = calloc(1, bsize);
108 if (mbr == NULL) {
109 rc = ENOMEM;
110 goto error;
111 }
112
113 rc = block_read_direct(sid, mbr_ba, 1, mbr);
114 if (rc != EOK) {
115 rc = EIO;
116 goto error;
117 }
118
119 label = calloc(1, sizeof(label_t));
120 if (label == NULL)
121 return ENOMEM;
122
123 list_initialize(&label->parts);
124
125 /* Verify boot record signature */
126 sgn = uint16_t_le2host(mbr->signature);
127 if (sgn != mbr_br_signature) {
128 rc = EIO;
129 goto error;
130 }
131
132 for (entry = 0; entry < mbr_nprimary; entry++) {
133 eptr = &mbr->pte[entry];
134 rc = mbr_pte_to_part(label, eptr, entry + 1);
135 if (rc != EOK)
136 goto error;
137 }
138
139 free(mbr);
140 mbr = NULL;
141
142 label->ops = &mbr_label_ops;
143 label->ltype = lt_mbr;
144 label->ablock0 = mbr_ablock0;
145 label->anblocks = nblocks - mbr_ablock0;
146 label->pri_entries = mbr_nprimary;
147 *rlabel = label;
148 return EOK;
149error:
150 free(mbr);
151 free(label);
152 return rc;
153}
154
155static int mbr_create(service_id_t sid, label_t **rlabel)
156{
157 return EOK;
158}
159
160static void mbr_close(label_t *label)
161{
162 free(label);
163}
164
165static int mbr_destroy(label_t *label)
166{
167 return EOK;
168}
169
170static int mbr_get_info(label_t *label, label_info_t *linfo)
171{
172 memset(linfo, 0, sizeof(label_info_t));
173 linfo->dcnt = dc_label;
174 linfo->ltype = lt_mbr;
175 linfo->ablock0 = label->ablock0;
176 linfo->anblocks = label->anblocks;
177 return EOK;
178}
179
180static label_part_t *mbr_part_first(label_t *label)
181{
182 link_t *link;
183
184 link = list_first(&label->parts);
185 if (link == NULL)
186 return NULL;
187
188 return list_get_instance(link, label_part_t, llabel);
189}
190
191static label_part_t *mbr_part_next(label_part_t *part)
192{
193 link_t *link;
194
195 link = list_next(&part->llabel, &part->label->parts);
196 if (link == NULL)
197 return NULL;
198
199 return list_get_instance(link, label_part_t, llabel);
200}
201
202static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
203{
204 pinfo->index = part->index;
205 pinfo->block0 = part->block0;
206 pinfo->nblocks = part->nblocks;
207}
208
209static int mbr_part_create(label_t *label, label_part_spec_t *pspec,
210 label_part_t **rpart)
211{
212 label_part_t *part;
213 mbr_pte_t pte;
214 int rc;
215
216 part = calloc(1, sizeof(label_part_t));
217 if (part == NULL)
218 return ENOMEM;
219
220 /* XXX Verify index, block0, nblocks */
221
222 if (pspec->index < 1 || pspec->index > label->pri_entries) {
223 rc = EINVAL;
224 goto error;
225 }
226
227 /* XXX Check if index is used */
228
229 part->label = label;
230 part->index = pspec->index;
231 part->block0 = pspec->block0;
232 part->nblocks = pspec->nblocks;
233 part->ptype = pspec->ptype;
234
235 rc = mbr_part_to_pte(part, &pte);
236 if (rc != EOK) {
237 rc = EINVAL;
238 goto error;
239 }
240
241 rc = mbr_pte_update(label, &pte, pspec->index - 1);
242 if (rc != EOK) {
243 rc = EIO;
244 goto error;
245 }
246
247 list_append(&part->llabel, &label->parts);
248
249 *rpart = part;
250 return EOK;
251error:
252 free(part);
253 return rc;
254}
255
256static int mbr_part_destroy(label_part_t *part)
257{
258 mbr_pte_t pte;
259 int rc;
260
261 /* Prepare unused partition table entry */
262 mbr_unused_pte(&pte);
263
264 /* Modify partition table */
265 rc = mbr_pte_update(part->label, &pte, part->index - 1);
266 if (rc != EOK)
267 return EIO;
268
269 list_remove(&part->llabel);
270 free(part);
271 return EOK;
272}
273
274static void mbr_unused_pte(mbr_pte_t *pte)
275{
276 memset(pte, 0, sizeof(mbr_pte_t));
277}
278
279static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
280{
281 if ((part->block0 >> 32) != 0)
282 return EINVAL;
283 if ((part->nblocks >> 32) != 0)
284 return EINVAL;
285 if ((part->ptype >> 8) != 0)
286 return EINVAL;
287
288 memset(pte, 0, sizeof(mbr_pte_t));
289 pte->ptype = part->ptype;
290 pte->first_lba = host2uint32_t_le(part->block0);
291 pte->length = host2uint32_t_le(part->nblocks);
292 return EOK;
293}
294
295static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
296{
297 label_part_t *part;
298 uint32_t block0;
299 uint32_t nblocks;
300
301 block0 = uint32_t_le2host(pte->first_lba);
302 nblocks = uint32_t_le2host(pte->length);
303
304 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
305 if (pte->ptype == mbr_pt_unused || pte->ptype == mbr_pt_extended ||
306 nblocks == 0)
307 return EOK;
308
309 part = calloc(1, sizeof(label_part_t));
310 if (part == NULL)
311 return ENOMEM;
312
313 part->index = index;
314 part->block0 = block0;
315 part->nblocks = nblocks;
316
317 /*
318 * TODO: Verify
319 * - partition must reside on disk
320 * - partition must not overlap any other partition
321 */
322
323 part->label = label;
324 list_append(&part->llabel, &label->parts);
325 return EOK;
326}
327
328/** Update partition table entry at specified index.
329 *
330 * Replace partition entry at index @a index with the contents of
331 * @a pte.
332 */
333static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
334{
335 mbr_br_block_t *br;
336 int rc;
337
338 br = calloc(1, label->block_size);
339 if (br == NULL)
340 return ENOMEM;
341
342 rc = block_read_direct(label->svcid, mbr_ba, 1, br);
343 if (rc != EOK) {
344 rc = EIO;
345 goto error;
346 }
347
348 br->pte[index] = *pte;
349
350 rc = block_write_direct(label->svcid, mbr_ba, 1, br);
351 if (rc != EOK) {
352 rc = EIO;
353 goto error;
354 }
355
356 free(br);
357 return EOK;
358error:
359 free(br);
360 return rc;
361}
362
363/** @}
364 */
Note: See TracBrowser for help on using the repository browser.