~youscribe/parted/3.1

« back to all changes in this revision

Viewing changes to libparted/labels/dvh.c

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    libparted - a library for manipulating disk partitions
 
3
    Copyright (C) 2001-2002, 2005, 2007-2012 Free Software Foundation, Inc.
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 3 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
*/
 
18
 
 
19
#include <config.h>
 
20
#include <parted/parted.h>
 
21
#include <parted/debug.h>
 
22
#include <parted/endian.h>
 
23
#include <stdbool.h>
 
24
 
 
25
#include "dvh.h"
 
26
#include "pt-tools.h"
 
27
 
 
28
#if ENABLE_NLS
 
29
#  include <libintl.h>
 
30
#  define _(String) dgettext (PACKAGE, String)
 
31
#else
 
32
#  define _(String) (String)
 
33
#endif /* ENABLE_NLS */
 
34
 
 
35
/* Default size for volhdr part, same val as IRIX's fx uses */
 
36
#define PTYPE_VOLHDR_DFLTSZ 4096
 
37
 
 
38
/* Partition numbers that seem to be strongly held convention */
 
39
#define PNUM_VOLHDR 8
 
40
#define PNUM_VOLUME 10
 
41
 
 
42
/* Other notes of interest:
 
43
 *  PED_PARTITION_EXTENDED is used for volume headers
 
44
 *  PED_PARTITION_LOGICAL  is used for bootfiles
 
45
 *  PED_PARTITION_NORMAL   is used for all else
 
46
 */
 
47
 
 
48
typedef struct _DVHDiskData {
 
49
        struct device_parameters        dev_params;
 
50
        int                             swap;   /* part num of swap, 0=none */
 
51
        int                             root;   /* part num of root, 0=none */
 
52
        int                             boot;   /* part num of boot, 0=none */
 
53
} DVHDiskData;
 
54
 
 
55
typedef struct _DVHPartData {
 
56
        int     type;
 
57
        char    name[VDNAMESIZE + 1];   /* boot volumes only */
 
58
        int     real_file_size;         /* boot volumes only */
 
59
} DVHPartData;
 
60
 
 
61
static PedDiskType dvh_disk_type;
 
62
 
 
63
static int
 
64
dvh_probe (const PedDevice *dev)
 
65
{
 
66
        struct volume_header *vh;
 
67
 
 
68
        void *label;
 
69
        if (!ptt_read_sector (dev, 0, &label))
 
70
                return 0;
 
71
 
 
72
        vh = (struct volume_header *) label;
 
73
 
 
74
        bool found = PED_BE32_TO_CPU (vh->vh_magic) == VHMAGIC;
 
75
        free (label);
 
76
        return found;
 
77
}
 
78
 
 
79
static PedDisk*
 
80
dvh_alloc (const PedDevice* dev)
 
81
{
 
82
        PedDisk*        disk;
 
83
        DVHDiskData*    dvh_disk_data;
 
84
        PedPartition*   volume_part;
 
85
        PedConstraint*  constraint_any;
 
86
 
 
87
        disk = _ped_disk_alloc (dev, &dvh_disk_type);
 
88
        if (!disk)
 
89
                goto error;
 
90
 
 
91
        disk->disk_specific = dvh_disk_data
 
92
                = ped_malloc (sizeof (DVHDiskData));
 
93
        if (!dvh_disk_data)
 
94
                goto error_free_disk;
 
95
 
 
96
        memset (&dvh_disk_data->dev_params, 0,
 
97
                sizeof (struct device_parameters));
 
98
        dvh_disk_data->swap = 0;
 
99
        dvh_disk_data->root = 0;
 
100
        dvh_disk_data->boot = 0;
 
101
 
 
102
        volume_part = ped_partition_new (disk, PED_PARTITION_EXTENDED, NULL,
 
103
                                         0, PTYPE_VOLHDR_DFLTSZ - 1);
 
104
        if (!volume_part)
 
105
                goto error_free_disk_specific;
 
106
        volume_part->num = PNUM_VOLHDR + 1;
 
107
        constraint_any = ped_constraint_any (dev);
 
108
        if (!ped_disk_add_partition (disk, volume_part, constraint_any))
 
109
                goto error_destroy_constraint_any;
 
110
        ped_constraint_destroy (constraint_any);
 
111
        return disk;
 
112
 
 
113
error_destroy_constraint_any:
 
114
        ped_constraint_destroy (constraint_any);
 
115
        ped_partition_destroy (volume_part);
 
116
error_free_disk_specific:
 
117
        free (disk->disk_specific);
 
118
error_free_disk:
 
119
        free (disk);
 
120
error:
 
121
        return NULL;
 
122
}
 
123
 
 
124
static PedDisk*
 
125
dvh_duplicate (const PedDisk* disk)
 
126
{
 
127
        PedDisk*        new_disk;
 
128
        DVHDiskData*    new_dvh_disk_data;
 
129
        DVHDiskData*    old_dvh_disk_data = disk->disk_specific;
 
130
 
 
131
        PED_ASSERT (old_dvh_disk_data != NULL);
 
132
 
 
133
        new_disk = ped_disk_new_fresh (disk->dev, &dvh_disk_type);
 
134
        if (!new_disk)
 
135
                goto error;
 
136
 
 
137
        new_disk->disk_specific = new_dvh_disk_data
 
138
                = ped_malloc (sizeof (DVHDiskData));
 
139
        if (!new_dvh_disk_data)
 
140
                goto error_free_new_disk;
 
141
 
 
142
        new_dvh_disk_data->dev_params = old_dvh_disk_data->dev_params;
 
143
        return new_disk;
 
144
 
 
145
error_free_new_disk:
 
146
        free (new_disk);
 
147
error:
 
148
        return NULL;
 
149
}
 
150
 
 
151
static void
 
152
dvh_free (PedDisk* disk)
 
153
{
 
154
        free (disk->disk_specific);
 
155
        _ped_disk_free (disk);
 
156
}
 
157
 
 
158
/* two's complement 32-bit checksum */
 
159
static uint32_t _GL_ATTRIBUTE_PURE
 
160
_checksum (const uint32_t* base, size_t size)
 
161
{
 
162
        uint32_t        sum = 0;
 
163
        size_t          i;
 
164
 
 
165
        for (i = 0; i < size / sizeof (uint32_t); i++)
 
166
                sum = sum - PED_BE32_TO_CPU (base[i]);
 
167
 
 
168
        return sum;
 
169
}
 
170
 
 
171
/* try to make a reasonable volume header partition... */
 
172
static PedExceptionOption
 
173
_handle_no_volume_header (PedDisk* disk)
 
174
{
 
175
        PedExceptionOption      ret;
 
176
        PedPartition*           part;
 
177
        PedConstraint*          constraint;
 
178
 
 
179
        switch (ped_exception_throw (
 
180
                PED_EXCEPTION_WARNING,
 
181
                PED_EXCEPTION_FIX + PED_EXCEPTION_CANCEL,
 
182
                _("%s has no extended partition (volume header partition)."),
 
183
                disk->dev->path)) {
 
184
                case PED_EXCEPTION_UNHANDLED:
 
185
                case PED_EXCEPTION_FIX:
 
186
                default:
 
187
                        part = ped_partition_new (
 
188
                                disk, PED_PARTITION_EXTENDED, NULL,
 
189
                                0, PTYPE_VOLHDR_DFLTSZ - 1);
 
190
                        if (!part)
 
191
                                goto error;
 
192
                        part->num = PNUM_VOLHDR + 1;
 
193
                        constraint = ped_constraint_any (part->disk->dev);
 
194
                        if (!constraint)
 
195
                                goto error_destroy_part;
 
196
                        if (!ped_disk_add_partition (disk, part, constraint))
 
197
                                goto error_destroy_constraint;
 
198
                        ped_constraint_destroy (constraint);
 
199
                        ret = PED_EXCEPTION_FIX;
 
200
                        break;
 
201
 
 
202
                case PED_EXCEPTION_CANCEL:
 
203
                        goto error;
 
204
        }
 
205
        return ret;
 
206
 
 
207
error_destroy_constraint:
 
208
        ped_constraint_destroy (constraint);
 
209
error_destroy_part:
 
210
        ped_partition_destroy (part);
 
211
error:
 
212
        return PED_EXCEPTION_CANCEL;
 
213
}
 
214
 
 
215
static PedPartition*
 
216
_parse_partition (PedDisk* disk, struct partition_table* pt)
 
217
{
 
218
        PedPartition*   part;
 
219
        DVHPartData*    dvh_part_data;
 
220
        PedSector       start = PED_BE32_TO_CPU (pt->pt_firstlbn);
 
221
        PedSector       length = PED_BE32_TO_CPU (pt->pt_nblks);
 
222
 
 
223
        part = ped_partition_new (disk,
 
224
                                  pt->pt_type ? 0 : PED_PARTITION_EXTENDED,
 
225
                                  NULL,
 
226
                                  start, start + length - 1);
 
227
        if (!part)
 
228
                return NULL;
 
229
 
 
230
        dvh_part_data = part->disk_specific;
 
231
        dvh_part_data->type = PED_BE32_TO_CPU (pt->pt_type);
 
232
        strcpy (dvh_part_data->name, "");
 
233
 
 
234
        return part;
 
235
}
 
236
 
 
237
static PedPartition*
 
238
_parse_boot_file (PedDisk* disk, struct volume_directory* vd)
 
239
{
 
240
        PedPartition*   part;
 
241
        DVHPartData*    dvh_part_data;
 
242
        PedSector       start = PED_BE32_TO_CPU (vd->vd_lbn);
 
243
        int             length = PED_BE32_TO_CPU (vd->vd_nbytes);
 
244
 
 
245
        part = ped_partition_new (disk, PED_PARTITION_LOGICAL, NULL,
 
246
                                  start, start + length/512 - 1);
 
247
        if (!part)
 
248
                return NULL;
 
249
 
 
250
        dvh_part_data = part->disk_specific;
 
251
        dvh_part_data->real_file_size = length;
 
252
 
 
253
        strncpy (dvh_part_data->name, vd->vd_name, VDNAMESIZE);
 
254
        dvh_part_data->name[VDNAMESIZE] = 0;
 
255
        return part;
 
256
}
 
257
 
 
258
static int dvh_write (const PedDisk* disk);
 
259
 
 
260
/* YUCK
 
261
 *
 
262
 *  If you remove a boot/root/swap partition, the disk->disk_specific
 
263
 * thing isn't updated.  (Probably reflects a design bug somewhere...)
 
264
 * Anyway, the workaround is: flush stale flags whenever we allocate
 
265
 * new partition numbers, and before we write to disk.
 
266
 */
 
267
static void
 
268
_flush_stale_flags (const PedDisk* disk)
 
269
{
 
270
        DVHDiskData*            dvh_disk_data = disk->disk_specific;
 
271
 
 
272
        if (dvh_disk_data->root
 
273
                       && !ped_disk_get_partition (disk, dvh_disk_data->root))
 
274
                dvh_disk_data->root = 0;
 
275
        if (dvh_disk_data->swap
 
276
                       && !ped_disk_get_partition (disk, dvh_disk_data->swap))
 
277
                dvh_disk_data->swap = 0;
 
278
        if (dvh_disk_data->boot
 
279
                       && !ped_disk_get_partition (disk, dvh_disk_data->boot))
 
280
                dvh_disk_data->boot = 0;
 
281
}
 
282
 
 
283
static int
 
284
dvh_read (PedDisk* disk)
 
285
{
 
286
        DVHDiskData*            dvh_disk_data = disk->disk_specific;
 
287
        int                     i;
 
288
        struct volume_header    vh;
 
289
        char                    boot_name [BFNAMESIZE + 1];
 
290
#ifndef DISCOVER_ONLY
 
291
        int                     write_back = 0;
 
292
#endif
 
293
 
 
294
        PED_ASSERT (dvh_disk_data != NULL);
 
295
 
 
296
        ped_disk_delete_all (disk);
 
297
 
 
298
        void *s0;
 
299
        if (!ptt_read_sector (disk->dev, 0, &s0))
 
300
                return 0;
 
301
        memcpy (&vh, s0, sizeof vh);
 
302
        free (s0);
 
303
 
 
304
        if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) {
 
305
                if (ped_exception_throw (
 
306
                        PED_EXCEPTION_ERROR,
 
307
                        PED_EXCEPTION_IGNORE_CANCEL,
 
308
                        _("Checksum is wrong, indicating the partition "
 
309
                          "table is corrupt."))
 
310
                                == PED_EXCEPTION_CANCEL)
 
311
                        return 0;
 
312
        }
 
313
 
 
314
        PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC);
 
315
 
 
316
        dvh_disk_data->dev_params = vh.vh_dp;
 
317
        strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE);
 
318
        boot_name[BFNAMESIZE] = 0;
 
319
 
 
320
        /* normal partitions */
 
321
        for (i = 0; i < NPARTAB; i++) {
 
322
                PedPartition* part;
 
323
 
 
324
                if (!vh.vh_pt[i].pt_nblks)
 
325
                        continue;
 
326
                /* Skip the whole-disk partition, parted disklikes overlap */
 
327
                if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME)
 
328
                        continue;
 
329
 
 
330
                part = _parse_partition (disk, &vh.vh_pt[i]);
 
331
                if (!part)
 
332
                        goto error_delete_all;
 
333
 
 
334
                part->fs_type = ped_file_system_probe (&part->geom);
 
335
                part->num = i + 1;
 
336
 
 
337
                if (PED_BE16_TO_CPU (vh.vh_rootpt) == i)
 
338
                        ped_partition_set_flag (part, PED_PARTITION_ROOT, 1);
 
339
                if (PED_BE16_TO_CPU (vh.vh_swappt) == i)
 
340
                        ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
 
341
 
 
342
                PedConstraint *constraint_exact
 
343
                  = ped_constraint_exact (&part->geom);
 
344
                bool ok = ped_disk_add_partition (disk, part, constraint_exact);
 
345
                ped_constraint_destroy (constraint_exact);
 
346
                if (!ok) {
 
347
                        ped_partition_destroy (part);
 
348
                        goto error_delete_all;
 
349
                }
 
350
        }
 
351
 
 
352
        if (!ped_disk_extended_partition (disk)) {
 
353
#ifdef DISCOVER_ONLY
 
354
                return 1;
 
355
#else
 
356
                switch (_handle_no_volume_header (disk)) {
 
357
                        case PED_EXCEPTION_CANCEL:
 
358
                                return 0;
 
359
                        case PED_EXCEPTION_IGNORE:
 
360
                                return 1;
 
361
                        case PED_EXCEPTION_FIX:
 
362
                                write_back = 1;
 
363
                                break;
 
364
                        default:
 
365
                                break;
 
366
                }
 
367
#endif
 
368
        }
 
369
 
 
370
        /* boot partitions */
 
371
        for (i = 0; i < NVDIR; i++) {
 
372
                PedPartition* part;
 
373
 
 
374
                if (!vh.vh_vd[i].vd_nbytes)
 
375
                        continue;
 
376
 
 
377
                part = _parse_boot_file (disk, &vh.vh_vd[i]);
 
378
                if (!part)
 
379
                        goto error_delete_all;
 
380
 
 
381
                part->fs_type = ped_file_system_probe (&part->geom);
 
382
                part->num = NPARTAB + i + 1;
 
383
 
 
384
                if (!strcmp (boot_name, ped_partition_get_name (part)))
 
385
                        ped_partition_set_flag (part, PED_PARTITION_BOOT, 1);
 
386
 
 
387
                PedConstraint *constraint_exact
 
388
                  = ped_constraint_exact (&part->geom);
 
389
                bool ok = ped_disk_add_partition (disk, part, constraint_exact);
 
390
                ped_constraint_destroy (constraint_exact);
 
391
                if (!ok) {
 
392
                        ped_partition_destroy (part);
 
393
                        goto error_delete_all;
 
394
                }
 
395
        }
 
396
#ifndef DISCOVER_ONLY
 
397
        if (write_back)
 
398
                dvh_write (disk);
 
399
#endif
 
400
        return 1;
 
401
 
 
402
error_delete_all:
 
403
        ped_disk_delete_all (disk);
 
404
        return 0;
 
405
}
 
406
 
 
407
#ifndef DISCOVER_ONLY
 
408
static void
 
409
_generate_partition (PedPartition* part, struct partition_table* pt)
 
410
{
 
411
        DVHPartData*    dvh_part_data = part->disk_specific;
 
412
 
 
413
        /* Assert not a bootfile */
 
414
        PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) == 0);
 
415
 
 
416
        pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length);
 
417
        pt->pt_firstlbn = PED_CPU_TO_BE32 (part->geom.start);
 
418
        pt->pt_type = PED_CPU_TO_BE32 (dvh_part_data->type);
 
419
}
 
420
 
 
421
static void
 
422
_generate_boot_file (PedPartition* part, struct volume_directory* vd)
 
423
{
 
424
        DVHPartData*    dvh_part_data = part->disk_specific;
 
425
 
 
426
        /* Assert it's a bootfile */
 
427
        PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) != 0);
 
428
 
 
429
        vd->vd_nbytes = PED_CPU_TO_BE32 (dvh_part_data->real_file_size);
 
430
        vd->vd_lbn = PED_CPU_TO_BE32 (part->geom.start);
 
431
 
 
432
        memset (vd->vd_name, 0, VDNAMESIZE);
 
433
        strncpy (vd->vd_name, dvh_part_data->name, VDNAMESIZE);
 
434
}
 
435
 
 
436
static int
 
437
dvh_write (const PedDisk* disk)
 
438
{
 
439
        DVHDiskData*            dvh_disk_data = disk->disk_specific;
 
440
        struct volume_header    vh;
 
441
        int                     i;
 
442
 
 
443
        PED_ASSERT (dvh_disk_data != NULL);
 
444
 
 
445
        _flush_stale_flags (disk);
 
446
 
 
447
        memset (&vh, 0, sizeof (struct volume_header));
 
448
 
 
449
        vh.vh_magic = PED_CPU_TO_BE32 (VHMAGIC);
 
450
        vh.vh_rootpt = PED_CPU_TO_BE16 (dvh_disk_data->root - 1);
 
451
        vh.vh_swappt = PED_CPU_TO_BE16 (dvh_disk_data->swap - 1);
 
452
 
 
453
        if (dvh_disk_data->boot) {
 
454
                PedPartition* boot_part;
 
455
                boot_part = ped_disk_get_partition (disk, dvh_disk_data->boot);
 
456
                strcpy (vh.vh_bootfile, ped_partition_get_name (boot_part));
 
457
        }
 
458
 
 
459
        vh.vh_dp = dvh_disk_data->dev_params;
 
460
        /* Set up rudimentary device geometry */
 
461
        vh.vh_dp.dp_cyls
 
462
                = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.cylinders);
 
463
        vh.vh_dp.dp_trks0 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.heads);
 
464
        vh.vh_dp.dp_secs
 
465
                = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.sectors);
 
466
        vh.vh_dp.dp_secbytes = PED_CPU_TO_BE16 ((short)disk->dev->sector_size);
 
467
 
 
468
        for (i = 0; i < NPARTAB; i++) {
 
469
                PedPartition* part = ped_disk_get_partition (disk, i + 1);
 
470
                if (part)
 
471
                        _generate_partition (part, &vh.vh_pt[i]);
 
472
        }
 
473
 
 
474
        /* whole disk partition
 
475
         * This is only ever written here, and never modified
 
476
         * (or even shown) as it must contain the entire disk,
 
477
         * and parted does not like overlapping partitions
 
478
         */
 
479
        vh.vh_pt[PNUM_VOLUME].pt_nblks = PED_CPU_TO_BE32 (disk->dev->length);
 
480
        vh.vh_pt[PNUM_VOLUME].pt_firstlbn = PED_CPU_TO_BE32 (0);
 
481
        vh.vh_pt[PNUM_VOLUME].pt_type = PED_CPU_TO_BE32 (PTYPE_VOLUME);
 
482
 
 
483
        for (i = 0; i < NVDIR; i++) {
 
484
                PedPartition* part = ped_disk_get_partition (disk,
 
485
                                                             i + 1 + NPARTAB);
 
486
                if (part)
 
487
                        _generate_boot_file (part, &vh.vh_vd[i]);
 
488
        }
 
489
 
 
490
        vh.vh_csum = 0;
 
491
        vh.vh_csum = PED_CPU_TO_BE32 (_checksum ((uint32_t*) &vh,
 
492
                                      sizeof (struct volume_header)));
 
493
 
 
494
        return (ptt_write_sector (disk, &vh, sizeof vh)
 
495
                && ped_device_sync (disk->dev));
 
496
}
 
497
#endif /* !DISCOVER_ONLY */
 
498
 
 
499
static PedPartition*
 
500
dvh_partition_new (const PedDisk* disk, PedPartitionType part_type,
 
501
                    const PedFileSystemType* fs_type,
 
502
                    PedSector start, PedSector end)
 
503
{
 
504
        PedPartition* part;
 
505
        DVHPartData* dvh_part_data;
 
506
 
 
507
        part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
 
508
        if (!part)
 
509
                goto error;
 
510
 
 
511
        if (!ped_partition_is_active (part)) {
 
512
                part->disk_specific = NULL;
 
513
                return part;
 
514
        }
 
515
 
 
516
        dvh_part_data = part->disk_specific =
 
517
                ped_malloc (sizeof (DVHPartData));
 
518
        if (!dvh_part_data)
 
519
                goto error_free_part;
 
520
 
 
521
        dvh_part_data->type = (part_type == PED_PARTITION_EXTENDED)
 
522
                                        ? PTYPE_VOLHDR
 
523
                                        : PTYPE_RAW;
 
524
        strcpy (dvh_part_data->name, "");
 
525
        dvh_part_data->real_file_size = part->geom.length * 512;
 
526
        return part;
 
527
 
 
528
error_free_part:
 
529
        _ped_partition_free (part);
 
530
error:
 
531
        return NULL;
 
532
}
 
533
 
 
534
static PedPartition*
 
535
dvh_partition_duplicate (const PedPartition* part)
 
536
{
 
537
        PedPartition* result;
 
538
        DVHPartData* part_data = part->disk_specific;
 
539
        DVHPartData* result_data;
 
540
 
 
541
        result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
 
542
                                       part->geom.start, part->geom.end);
 
543
        if (!result)
 
544
                goto error;
 
545
        result->num = part->num;
 
546
 
 
547
        if (!ped_partition_is_active (part)) {
 
548
                result->disk_specific = NULL;
 
549
                return result;
 
550
        }
 
551
 
 
552
        result_data = result->disk_specific =
 
553
                ped_malloc (sizeof (DVHPartData));
 
554
        if (!result_data)
 
555
                goto error_free_part;
 
556
 
 
557
        result_data->type = part_data->type;
 
558
        strcpy (result_data->name, part_data->name);
 
559
        result_data->real_file_size = part_data->real_file_size;
 
560
        return result;
 
561
 
 
562
error_free_part:
 
563
        _ped_partition_free (result);
 
564
error:
 
565
        return NULL;
 
566
}
 
567
 
 
568
static void
 
569
dvh_partition_destroy (PedPartition* part)
 
570
{
 
571
        if (ped_partition_is_active (part)) {
 
572
                PED_ASSERT (part->disk_specific != NULL);
 
573
                free (part->disk_specific);
 
574
        }
 
575
        _ped_partition_free (part);
 
576
}
 
577
 
 
578
static int
 
579
dvh_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
 
580
{
 
581
        DVHPartData* dvh_part_data = part->disk_specific;
 
582
 
 
583
        part->fs_type = fs_type;
 
584
 
 
585
        if (part->type == PED_PARTITION_EXTENDED) {
 
586
                dvh_part_data->type = PTYPE_VOLHDR;
 
587
                return 1;
 
588
        }
 
589
 
 
590
        /* Is this a bootfile? */
 
591
        if (part->type == PED_PARTITION_LOGICAL)
 
592
                return 1;
 
593
 
 
594
        if (fs_type && !strcmp (fs_type->name, "xfs"))
 
595
                dvh_part_data->type = PTYPE_XFS;
 
596
        else
 
597
                dvh_part_data->type = PTYPE_RAW;
 
598
        return 1;
 
599
}
 
600
 
 
601
static int
 
602
dvh_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
 
603
{
 
604
        DVHDiskData* dvh_disk_data = part->disk->disk_specific;
 
605
 
 
606
        switch (flag) {
 
607
        case PED_PARTITION_ROOT:
 
608
                if (part->type != 0 && state) {
 
609
#ifndef DISCOVER_ONLY
 
610
                        ped_exception_throw (
 
611
                                PED_EXCEPTION_ERROR,
 
612
                                PED_EXCEPTION_CANCEL,
 
613
                                _("Only primary partitions can be root "
 
614
                                  "partitions."));
 
615
#endif
 
616
                        return 0;
 
617
                }
 
618
                dvh_disk_data->root = state ? part->num : 0;
 
619
                break;
 
620
 
 
621
        case PED_PARTITION_SWAP:
 
622
                if (part->type != 0 && state) {
 
623
#ifndef DISCOVER_ONLY
 
624
                        ped_exception_throw (
 
625
                                PED_EXCEPTION_ERROR,
 
626
                                PED_EXCEPTION_CANCEL,
 
627
                                _("Only primary partitions can be swap "
 
628
                                  "partitions."));
 
629
                        return 0;
 
630
#endif
 
631
                }
 
632
                dvh_disk_data->swap = state ? part->num : 0;
 
633
                break;
 
634
 
 
635
        case PED_PARTITION_BOOT:
 
636
                if (part->type != PED_PARTITION_LOGICAL && state) {
 
637
#ifndef DISCOVER_ONLY
 
638
                        ped_exception_throw (
 
639
                                PED_EXCEPTION_ERROR,
 
640
                                PED_EXCEPTION_CANCEL,
 
641
                                _("Only logical partitions can be a boot "
 
642
                                  "file."));
 
643
#endif
 
644
                        return 0;
 
645
                }
 
646
                dvh_disk_data->boot = state ? part->num : 0;
 
647
                break;
 
648
 
 
649
        case PED_PARTITION_LVM:
 
650
        case PED_PARTITION_LBA:
 
651
        case PED_PARTITION_HIDDEN:
 
652
        case PED_PARTITION_RAID:
 
653
        default:
 
654
                return 0;
 
655
        }
 
656
        return 1;
 
657
}
 
658
 
 
659
static int _GL_ATTRIBUTE_PURE
 
660
dvh_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
 
661
{
 
662
        DVHDiskData* dvh_disk_data = part->disk->disk_specific;
 
663
 
 
664
        switch (flag) {
 
665
        case PED_PARTITION_ROOT:
 
666
                return dvh_disk_data->root == part->num;
 
667
 
 
668
        case PED_PARTITION_SWAP:
 
669
                return dvh_disk_data->swap == part->num;
 
670
 
 
671
        case PED_PARTITION_BOOT:
 
672
                return dvh_disk_data->boot == part->num;
 
673
 
 
674
        case PED_PARTITION_LVM:
 
675
        case PED_PARTITION_LBA:
 
676
        case PED_PARTITION_HIDDEN:
 
677
        case PED_PARTITION_RAID:
 
678
        default:
 
679
                return 0;
 
680
        }
 
681
        return 1;
 
682
}
 
683
 
 
684
static int
 
685
dvh_partition_is_flag_available (const PedPartition* part,
 
686
                                  PedPartitionFlag flag)
 
687
{
 
688
        switch (flag) {
 
689
        case PED_PARTITION_ROOT:
 
690
        case PED_PARTITION_SWAP:
 
691
        case PED_PARTITION_BOOT:
 
692
                return 1;
 
693
 
 
694
        case PED_PARTITION_LVM:
 
695
        case PED_PARTITION_LBA:
 
696
        case PED_PARTITION_HIDDEN:
 
697
        case PED_PARTITION_RAID:
 
698
        default:
 
699
                return 0;
 
700
        }
 
701
        return 1;
 
702
}
 
703
 
 
704
static void
 
705
dvh_partition_set_name (PedPartition* part, const char* name)
 
706
{
 
707
        DVHPartData* dvh_part_data = part->disk_specific;
 
708
 
 
709
        if (part->type == PED_PARTITION_LOGICAL) {
 
710
                /* Bootfile */
 
711
                strncpy (dvh_part_data->name, name, VDNAMESIZE);
 
712
                dvh_part_data->name[VDNAMESIZE] = 0;
 
713
        } else {
 
714
#ifndef DISCOVER_ONLY
 
715
                ped_exception_throw (
 
716
                        PED_EXCEPTION_ERROR,
 
717
                        PED_EXCEPTION_CANCEL,
 
718
                        _("failed to set dvh partition name to %s:\n"
 
719
                          "Only logical partitions (boot files) have a name."),
 
720
                        name);
 
721
#endif
 
722
        }
 
723
}
 
724
 
 
725
static const char*
 
726
dvh_partition_get_name (const PedPartition* part)
 
727
{
 
728
        DVHPartData* dvh_part_data = part->disk_specific;
 
729
        return dvh_part_data->name;
 
730
}
 
731
 
 
732
/* The constraint for the volume header partition is different, because it must
 
733
 * contain the first sector of the disk.
 
734
 */
 
735
static PedConstraint*
 
736
_get_extended_constraint (PedDisk* disk)
 
737
{
 
738
        PedGeometry     min_geom;
 
739
        if (!ped_geometry_init (&min_geom, disk->dev, 0, 1))
 
740
                return NULL;
 
741
        return ped_constraint_new_from_min (&min_geom);
 
742
}
 
743
 
 
744
static PedConstraint*
 
745
_get_primary_constraint (PedDisk* disk)
 
746
{
 
747
        PedGeometry     max_geom;
 
748
        if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
 
749
                return NULL;
 
750
        return ped_constraint_new_from_max (&max_geom);
 
751
}
 
752
 
 
753
static int
 
754
dvh_partition_align (PedPartition* part, const PedConstraint* constraint)
 
755
{
 
756
        PED_ASSERT (part != NULL);
 
757
 
 
758
        if (_ped_partition_attempt_align (
 
759
                        part, constraint,
 
760
                        (part->type == PED_PARTITION_EXTENDED)
 
761
                                ? _get_extended_constraint (part->disk)
 
762
                                : _get_primary_constraint (part->disk)))
 
763
                return 1;
 
764
 
 
765
#ifndef DISCOVER_ONLY
 
766
        ped_exception_throw (
 
767
                PED_EXCEPTION_ERROR,
 
768
                PED_EXCEPTION_CANCEL,
 
769
                _("Unable to satisfy all constraints on the partition."));
 
770
#endif
 
771
        return 0;
 
772
}
 
773
 
 
774
static int
 
775
dvh_partition_enumerate (PedPartition* part)
 
776
{
 
777
        int i;
 
778
 
 
779
        /* never change the partition numbers */
 
780
        if (part->num != -1)
 
781
                return 1;
 
782
 
 
783
        _flush_stale_flags (part->disk);
 
784
 
 
785
        if (part->type & PED_PARTITION_LOGICAL) {
 
786
                /* Bootfile */
 
787
                for (i = 1 + NPARTAB; i <= NPARTAB + NVDIR; i++) {
 
788
                        if (!ped_disk_get_partition (part->disk, i)) {
 
789
                                part->num = i;
 
790
                                return 1;
 
791
                        }
 
792
                }
 
793
                PED_ASSERT (0);
 
794
        } else if (part->type & PED_PARTITION_EXTENDED) {
 
795
                /* Volheader */
 
796
                part->num = PNUM_VOLHDR + 1;
 
797
        } else {
 
798
                for (i = 1; i <= NPARTAB; i++) {
 
799
                        /* reserved for full volume partition */
 
800
                        if (i == PNUM_VOLUME + 1)
 
801
                                continue;
 
802
 
 
803
                        if (!ped_disk_get_partition (part->disk, i)) {
 
804
                                part->num = i;
 
805
                                return 1;
 
806
                        }
 
807
                }
 
808
                ped_exception_throw (
 
809
                        PED_EXCEPTION_ERROR,
 
810
                        PED_EXCEPTION_CANCEL,
 
811
                        _("Too many primary partitions"));
 
812
        }
 
813
 
 
814
        return 0;
 
815
}
 
816
 
 
817
static int
 
818
dvh_get_max_primary_partition_count (const PedDisk* disk)
 
819
{
 
820
        return NPARTAB;
 
821
}
 
822
 
 
823
static bool
 
824
dvh_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
 
825
{
 
826
        *max_n = NPARTAB;
 
827
        return true;
 
828
}
 
829
 
 
830
 
 
831
static int
 
832
dvh_alloc_metadata (PedDisk* disk)
 
833
{
 
834
        PedPartition* part;
 
835
        PedPartition* extended_part;
 
836
        PedPartitionType metadata_type;
 
837
        PED_ASSERT(disk != NULL);
 
838
 
 
839
        /* We don't need to "protect" the start of the disk from the volume
 
840
         * header.
 
841
         */
 
842
        extended_part = ped_disk_extended_partition (disk);
 
843
        if (extended_part && extended_part->geom.start == 0)
 
844
                metadata_type = PED_PARTITION_METADATA | PED_PARTITION_LOGICAL;
 
845
        else
 
846
                metadata_type = PED_PARTITION_METADATA;
 
847
 
 
848
        part = ped_partition_new (disk, metadata_type, NULL, 0, 0);
 
849
        if (!part)
 
850
                goto error;
 
851
 
 
852
        PedConstraint *constraint_exact
 
853
          = ped_constraint_exact (&part->geom);
 
854
        bool ok = ped_disk_add_partition (disk, part, constraint_exact);
 
855
        ped_constraint_destroy (constraint_exact);
 
856
        if (ok)
 
857
                return 1;
 
858
 
 
859
        ped_partition_destroy (part);
 
860
error:
 
861
        return 0;
 
862
}
 
863
 
 
864
#include "pt-common.h"
 
865
PT_define_limit_functions (dvh)
 
866
 
 
867
static PedDiskOps dvh_disk_ops = {
 
868
        clobber:                NULL,
 
869
        write:                  NULL_IF_DISCOVER_ONLY (dvh_write),
 
870
 
 
871
        partition_set_name:     dvh_partition_set_name,
 
872
        partition_get_name:     dvh_partition_get_name,
 
873
        PT_op_function_initializers (dvh)
 
874
};
 
875
 
 
876
static PedDiskType dvh_disk_type = {
 
877
        next:           NULL,
 
878
        name:           "dvh",
 
879
        ops:            &dvh_disk_ops,
 
880
        features:       PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_EXTENDED
 
881
};
 
882
 
 
883
void
 
884
ped_disk_dvh_init ()
 
885
{
 
886
        PED_ASSERT (sizeof (struct volume_header) == 512);
 
887
 
 
888
        ped_disk_type_register (&dvh_disk_type);
 
889
}
 
890
 
 
891
void
 
892
ped_disk_dvh_done ()
 
893
{
 
894
        ped_disk_type_unregister (&dvh_disk_type);
 
895
}