The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/part/g_part_gpt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar
    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  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. 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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.3/sys/geom/part/g_part_gpt.c 223816 2011-07-06 05:40:22Z ae $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/bio.h>
   32 #include <sys/diskmbr.h>
   33 #include <sys/endian.h>
   34 #include <sys/gpt.h>
   35 #include <sys/kernel.h>
   36 #include <sys/kobj.h>
   37 #include <sys/limits.h>
   38 #include <sys/lock.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mutex.h>
   41 #include <sys/queue.h>
   42 #include <sys/sbuf.h>
   43 #include <sys/systm.h>
   44 #include <sys/uuid.h>
   45 #include <geom/geom.h>
   46 #include <geom/part/g_part.h>
   47 
   48 #include "g_part_if.h"
   49 
   50 CTASSERT(offsetof(struct gpt_hdr, padding) == 92);
   51 CTASSERT(sizeof(struct gpt_ent) == 128);
   52 
   53 #define EQUUID(a,b)     (memcmp(a, b, sizeof(struct uuid)) == 0)
   54 
   55 #define MBRSIZE         512
   56 
   57 enum gpt_elt {
   58         GPT_ELT_PRIHDR,
   59         GPT_ELT_PRITBL,
   60         GPT_ELT_SECHDR,
   61         GPT_ELT_SECTBL,
   62         GPT_ELT_COUNT
   63 };
   64 
   65 enum gpt_state {
   66         GPT_STATE_UNKNOWN,      /* Not determined. */
   67         GPT_STATE_MISSING,      /* No signature found. */
   68         GPT_STATE_CORRUPT,      /* Checksum mismatch. */
   69         GPT_STATE_INVALID,      /* Nonconformant/invalid. */
   70         GPT_STATE_OK            /* Perfectly fine. */
   71 };
   72 
   73 struct g_part_gpt_table {
   74         struct g_part_table     base;
   75         u_char                  mbr[MBRSIZE];
   76         struct gpt_hdr          *hdr;
   77         quad_t                  lba[GPT_ELT_COUNT];
   78         enum gpt_state          state[GPT_ELT_COUNT];
   79 };
   80 
   81 struct g_part_gpt_entry {
   82         struct g_part_entry     base;
   83         struct gpt_ent          ent;
   84 };
   85 
   86 static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t);
   87 static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t);
   88 static void g_gpt_set_defaults(struct g_part_table *, struct g_provider *);
   89 
   90 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
   91     struct g_part_parms *);
   92 static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *);
   93 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
   94 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
   95 static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *,
   96     struct sbuf *, const char *);
   97 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
   98 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
   99     struct g_part_parms *);
  100 static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
  101     char *, size_t);
  102 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
  103 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
  104 static int g_part_gpt_setunset(struct g_part_table *table,
  105     struct g_part_entry *baseentry, const char *attrib, unsigned int set);
  106 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
  107     char *, size_t);
  108 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
  109 static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *,
  110     struct g_part_parms *);
  111 static int g_part_gpt_recover(struct g_part_table *);
  112 
  113 static kobj_method_t g_part_gpt_methods[] = {
  114         KOBJMETHOD(g_part_add,          g_part_gpt_add),
  115         KOBJMETHOD(g_part_bootcode,     g_part_gpt_bootcode),
  116         KOBJMETHOD(g_part_create,       g_part_gpt_create),
  117         KOBJMETHOD(g_part_destroy,      g_part_gpt_destroy),
  118         KOBJMETHOD(g_part_dumpconf,     g_part_gpt_dumpconf),
  119         KOBJMETHOD(g_part_dumpto,       g_part_gpt_dumpto),
  120         KOBJMETHOD(g_part_modify,       g_part_gpt_modify),
  121         KOBJMETHOD(g_part_resize,       g_part_gpt_resize),
  122         KOBJMETHOD(g_part_name,         g_part_gpt_name),
  123         KOBJMETHOD(g_part_probe,        g_part_gpt_probe),
  124         KOBJMETHOD(g_part_read,         g_part_gpt_read),
  125         KOBJMETHOD(g_part_recover,      g_part_gpt_recover),
  126         KOBJMETHOD(g_part_setunset,     g_part_gpt_setunset),
  127         KOBJMETHOD(g_part_type,         g_part_gpt_type),
  128         KOBJMETHOD(g_part_write,        g_part_gpt_write),
  129         { 0, 0 }
  130 };
  131 
  132 static struct g_part_scheme g_part_gpt_scheme = {
  133         "GPT",
  134         g_part_gpt_methods,
  135         sizeof(struct g_part_gpt_table),
  136         .gps_entrysz = sizeof(struct g_part_gpt_entry),
  137         .gps_minent = 128,
  138         .gps_maxent = 4096,
  139         .gps_bootcodesz = MBRSIZE,
  140 };
  141 G_PART_SCHEME_DECLARE(g_part_gpt);
  142 
  143 static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT;
  144 static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS;
  145 static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL;
  146 static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID;
  147 static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE;
  148 static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY;
  149 static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS;
  150 static struct uuid gpt_uuid_bios_boot = GPT_ENT_TYPE_BIOS_BOOT;
  151 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
  152 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
  153 static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
  154 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
  155 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
  156 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
  157 static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
  158 static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA;
  159 static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM;
  160 static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID;
  161 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
  162 static struct uuid gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
  163 static struct uuid gpt_uuid_ms_reserved = GPT_ENT_TYPE_MS_RESERVED;
  164 static struct uuid gpt_uuid_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA;
  165 static struct uuid gpt_uuid_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA;
  166 static struct uuid gpt_uuid_netbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD;
  167 static struct uuid gpt_uuid_netbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD;
  168 static struct uuid gpt_uuid_netbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
  169 static struct uuid gpt_uuid_netbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
  170 static struct uuid gpt_uuid_netbsd_raid = GPT_ENT_TYPE_NETBSD_RAID;
  171 static struct uuid gpt_uuid_netbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
  172 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
  173 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
  174 
  175 static struct g_part_uuid_alias {
  176         struct uuid *uuid;
  177         int alias;
  178 } gpt_uuid_alias_match[] = {
  179         { &gpt_uuid_apple_boot,         G_PART_ALIAS_APPLE_BOOT },
  180         { &gpt_uuid_apple_hfs,          G_PART_ALIAS_APPLE_HFS },
  181         { &gpt_uuid_apple_label,        G_PART_ALIAS_APPLE_LABEL },
  182         { &gpt_uuid_apple_raid,         G_PART_ALIAS_APPLE_RAID },
  183         { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE },
  184         { &gpt_uuid_apple_tv_recovery,  G_PART_ALIAS_APPLE_TV_RECOVERY },
  185         { &gpt_uuid_apple_ufs,          G_PART_ALIAS_APPLE_UFS },
  186         { &gpt_uuid_bios_boot,          G_PART_ALIAS_BIOS_BOOT },
  187         { &gpt_uuid_efi,                G_PART_ALIAS_EFI },
  188         { &gpt_uuid_freebsd,            G_PART_ALIAS_FREEBSD },
  189         { &gpt_uuid_freebsd_boot,       G_PART_ALIAS_FREEBSD_BOOT },
  190         { &gpt_uuid_freebsd_swap,       G_PART_ALIAS_FREEBSD_SWAP },
  191         { &gpt_uuid_freebsd_ufs,        G_PART_ALIAS_FREEBSD_UFS },
  192         { &gpt_uuid_freebsd_vinum,      G_PART_ALIAS_FREEBSD_VINUM },
  193         { &gpt_uuid_freebsd_zfs,        G_PART_ALIAS_FREEBSD_ZFS },
  194         { &gpt_uuid_linux_data,         G_PART_ALIAS_LINUX_DATA },
  195         { &gpt_uuid_linux_lvm,          G_PART_ALIAS_LINUX_LVM },
  196         { &gpt_uuid_linux_raid,         G_PART_ALIAS_LINUX_RAID },
  197         { &gpt_uuid_linux_swap,         G_PART_ALIAS_LINUX_SWAP },
  198         { &gpt_uuid_mbr,                G_PART_ALIAS_MBR },
  199         { &gpt_uuid_ms_basic_data,      G_PART_ALIAS_MS_BASIC_DATA },
  200         { &gpt_uuid_ms_ldm_data,        G_PART_ALIAS_MS_LDM_DATA },
  201         { &gpt_uuid_ms_ldm_metadata,    G_PART_ALIAS_MS_LDM_METADATA },
  202         { &gpt_uuid_ms_reserved,        G_PART_ALIAS_MS_RESERVED },
  203         { &gpt_uuid_netbsd_ccd,         G_PART_ALIAS_NETBSD_CCD },
  204         { &gpt_uuid_netbsd_cgd,         G_PART_ALIAS_NETBSD_CGD },
  205         { &gpt_uuid_netbsd_ffs,         G_PART_ALIAS_NETBSD_FFS },
  206         { &gpt_uuid_netbsd_lfs,         G_PART_ALIAS_NETBSD_LFS },
  207         { &gpt_uuid_netbsd_raid,        G_PART_ALIAS_NETBSD_RAID },
  208         { &gpt_uuid_netbsd_swap,        G_PART_ALIAS_NETBSD_SWAP },
  209 
  210         { NULL, 0 }
  211 };
  212 
  213 static struct gpt_hdr *
  214 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
  215     enum gpt_elt elt)
  216 {
  217         struct gpt_hdr *buf, *hdr;
  218         struct g_provider *pp;
  219         quad_t lba, last;
  220         int error;
  221         uint32_t crc, sz;
  222 
  223         pp = cp->provider;
  224         last = (pp->mediasize / pp->sectorsize) - 1;
  225         table->state[elt] = GPT_STATE_MISSING;
  226         /*
  227          * If the primary header is valid look for secondary
  228          * header in AlternateLBA, otherwise in the last medium's LBA.
  229          */
  230         if (elt == GPT_ELT_SECHDR) {
  231                 if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK)
  232                         table->lba[elt] = last;
  233         } else
  234                 table->lba[elt] = 1;
  235         buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
  236             &error);
  237         if (buf == NULL)
  238                 return (NULL);
  239         hdr = NULL;
  240         if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
  241                 goto fail;
  242 
  243         table->state[elt] = GPT_STATE_CORRUPT;
  244         sz = le32toh(buf->hdr_size);
  245         if (sz < 92 || sz > pp->sectorsize)
  246                 goto fail;
  247 
  248         hdr = g_malloc(sz, M_WAITOK | M_ZERO);
  249         bcopy(buf, hdr, sz);
  250         hdr->hdr_size = sz;
  251 
  252         crc = le32toh(buf->hdr_crc_self);
  253         buf->hdr_crc_self = 0;
  254         if (crc32(buf, sz) != crc)
  255                 goto fail;
  256         hdr->hdr_crc_self = crc;
  257 
  258         table->state[elt] = GPT_STATE_INVALID;
  259         hdr->hdr_revision = le32toh(buf->hdr_revision);
  260         if (hdr->hdr_revision < GPT_HDR_REVISION)
  261                 goto fail;
  262         hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
  263         if (hdr->hdr_lba_self != table->lba[elt])
  264                 goto fail;
  265         hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
  266         if (hdr->hdr_lba_alt == hdr->hdr_lba_self ||
  267             hdr->hdr_lba_alt > last)
  268                 goto fail;
  269 
  270         /* Check the managed area. */
  271         hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
  272         if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
  273                 goto fail;
  274         hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
  275         if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
  276                 goto fail;
  277 
  278         /* Check the table location and size of the table. */
  279         hdr->hdr_entries = le32toh(buf->hdr_entries);
  280         hdr->hdr_entsz = le32toh(buf->hdr_entsz);
  281         if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
  282             (hdr->hdr_entsz & 7) != 0)
  283                 goto fail;
  284         hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
  285         if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
  286                 goto fail;
  287         if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
  288             hdr->hdr_lba_table <= hdr->hdr_lba_end)
  289                 goto fail;
  290         lba = hdr->hdr_lba_table +
  291             (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
  292             pp->sectorsize - 1;
  293         if (lba >= last)
  294                 goto fail;
  295         if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
  296                 goto fail;
  297 
  298         table->state[elt] = GPT_STATE_OK;
  299         le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
  300         hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
  301 
  302         /* save LBA for secondary header */
  303         if (elt == GPT_ELT_PRIHDR)
  304                 table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt;
  305 
  306         g_free(buf);
  307         return (hdr);
  308 
  309  fail:
  310         if (hdr != NULL)
  311                 g_free(hdr);
  312         g_free(buf);
  313         return (NULL);
  314 }
  315 
  316 static struct gpt_ent *
  317 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
  318     enum gpt_elt elt, struct gpt_hdr *hdr)
  319 {
  320         struct g_provider *pp;
  321         struct gpt_ent *ent, *tbl;
  322         char *buf, *p;
  323         unsigned int idx, sectors, tblsz, size;
  324         int error;
  325 
  326         if (hdr == NULL)
  327                 return (NULL);
  328 
  329         pp = cp->provider;
  330         table->lba[elt] = hdr->hdr_lba_table;
  331 
  332         table->state[elt] = GPT_STATE_MISSING;
  333         tblsz = hdr->hdr_entries * hdr->hdr_entsz;
  334         sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
  335         buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
  336         for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
  337                 size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
  338                     (sectors - idx) * pp->sectorsize;
  339                 p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
  340                     size, &error);
  341                 if (p == NULL) {
  342                         g_free(buf);
  343                         return (NULL);
  344                 }
  345                 bcopy(p, buf + idx * pp->sectorsize, size);
  346                 g_free(p);
  347         }
  348         table->state[elt] = GPT_STATE_CORRUPT;
  349         if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
  350                 g_free(buf);
  351                 return (NULL);
  352         }
  353 
  354         table->state[elt] = GPT_STATE_OK;
  355         tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
  356             M_WAITOK | M_ZERO);
  357 
  358         for (idx = 0, ent = tbl, p = buf;
  359              idx < hdr->hdr_entries;
  360              idx++, ent++, p += hdr->hdr_entsz) {
  361                 le_uuid_dec(p, &ent->ent_type);
  362                 le_uuid_dec(p + 16, &ent->ent_uuid);
  363                 ent->ent_lba_start = le64dec(p + 32);
  364                 ent->ent_lba_end = le64dec(p + 40);
  365                 ent->ent_attr = le64dec(p + 48);
  366                 /* Keep UTF-16 in little-endian. */
  367                 bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name));
  368         }
  369 
  370         g_free(buf);
  371         return (tbl);
  372 }
  373 
  374 static int
  375 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
  376 {
  377 
  378         if (pri == NULL || sec == NULL)
  379                 return (0);
  380 
  381         if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
  382                 return (0);
  383         return ((pri->hdr_revision == sec->hdr_revision &&
  384             pri->hdr_size == sec->hdr_size &&
  385             pri->hdr_lba_start == sec->hdr_lba_start &&
  386             pri->hdr_lba_end == sec->hdr_lba_end &&
  387             pri->hdr_entries == sec->hdr_entries &&
  388             pri->hdr_entsz == sec->hdr_entsz &&
  389             pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
  390 }
  391 
  392 static int
  393 gpt_parse_type(const char *type, struct uuid *uuid)
  394 {
  395         struct uuid tmp;
  396         const char *alias;
  397         int error;
  398         struct g_part_uuid_alias *uap;
  399 
  400         if (type[0] == '!') {
  401                 error = parse_uuid(type + 1, &tmp);
  402                 if (error)
  403                         return (error);
  404                 if (EQUUID(&tmp, &gpt_uuid_unused))
  405                         return (EINVAL);
  406                 *uuid = tmp;
  407                 return (0);
  408         }
  409         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) {
  410                 alias = g_part_alias_name(uap->alias);
  411                 if (!strcasecmp(type, alias)) {
  412                         *uuid = *uap->uuid;
  413                         return (0);
  414                 }
  415         }
  416         return (EINVAL);
  417 }
  418 
  419 static int
  420 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
  421     struct g_part_parms *gpp)
  422 {
  423         struct g_part_gpt_entry *entry;
  424         int error;
  425 
  426         entry = (struct g_part_gpt_entry *)baseentry;
  427         error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
  428         if (error)
  429                 return (error);
  430         kern_uuidgen(&entry->ent.ent_uuid, 1);
  431         entry->ent.ent_lba_start = baseentry->gpe_start;
  432         entry->ent.ent_lba_end = baseentry->gpe_end;
  433         if (baseentry->gpe_deleted) {
  434                 entry->ent.ent_attr = 0;
  435                 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
  436         }
  437         if (gpp->gpp_parms & G_PART_PARM_LABEL)
  438                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
  439                     sizeof(entry->ent.ent_name) /
  440                     sizeof(entry->ent.ent_name[0]));
  441         return (0);
  442 }
  443 
  444 static int
  445 g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
  446 {
  447         struct g_part_gpt_table *table;
  448         size_t codesz;
  449 
  450         codesz = DOSPARTOFF;
  451         table = (struct g_part_gpt_table *)basetable;
  452         bzero(table->mbr, codesz);
  453         codesz = MIN(codesz, gpp->gpp_codesize);
  454         if (codesz > 0)
  455                 bcopy(gpp->gpp_codeptr, table->mbr, codesz);
  456 
  457         /* Mark the PMBR active since some BIOS require it */
  458         table->mbr[DOSPARTOFF] = 0x80;          /* status */
  459         return (0);
  460 }
  461 
  462 static int
  463 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
  464 {
  465         struct g_provider *pp;
  466         struct g_part_gpt_table *table;
  467         quad_t last;
  468         size_t tblsz;
  469 
  470         /* We don't nest, which means that our depth should be 0. */
  471         if (basetable->gpt_depth != 0)
  472                 return (ENXIO);
  473 
  474         table = (struct g_part_gpt_table *)basetable;
  475         pp = gpp->gpp_provider;
  476         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
  477             pp->sectorsize - 1) / pp->sectorsize;
  478         if (pp->sectorsize < MBRSIZE ||
  479             pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
  480             pp->sectorsize)
  481                 return (ENOSPC);
  482 
  483         last = (pp->mediasize / pp->sectorsize) - 1;
  484 
  485         le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC);
  486         table->mbr[DOSPARTOFF + 1] = 0x01;              /* shd */
  487         table->mbr[DOSPARTOFF + 2] = 0x01;              /* ssect */
  488         table->mbr[DOSPARTOFF + 3] = 0x00;              /* scyl */
  489         table->mbr[DOSPARTOFF + 4] = 0xee;              /* typ */
  490         table->mbr[DOSPARTOFF + 5] = 0xff;              /* ehd */
  491         table->mbr[DOSPARTOFF + 6] = 0xff;              /* esect */
  492         table->mbr[DOSPARTOFF + 7] = 0xff;              /* ecyl */
  493         le32enc(table->mbr + DOSPARTOFF + 8, 1);        /* start */
  494         le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, UINT32_MAX));
  495 
  496         /* Allocate space for the header */
  497         table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
  498 
  499         bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
  500         table->hdr->hdr_revision = GPT_HDR_REVISION;
  501         table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
  502         kern_uuidgen(&table->hdr->hdr_uuid, 1);
  503         table->hdr->hdr_entries = basetable->gpt_entries;
  504         table->hdr->hdr_entsz = sizeof(struct gpt_ent);
  505 
  506         g_gpt_set_defaults(basetable, pp);
  507         return (0);
  508 }
  509 
  510 static int
  511 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
  512 {
  513         struct g_part_gpt_table *table;
  514         struct g_provider *pp;
  515 
  516         table = (struct g_part_gpt_table *)basetable;
  517         pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
  518         g_free(table->hdr);
  519         table->hdr = NULL;
  520 
  521         /*
  522          * Wipe the first 2 sectors to clear the partitioning. Wipe the last
  523          * sector only if it has valid secondary header.
  524          */
  525         basetable->gpt_smhead |= 3;
  526         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
  527             table->lba[GPT_ELT_SECHDR] == pp->mediasize / pp->sectorsize - 1)
  528                 basetable->gpt_smtail |= 1;
  529         return (0);
  530 }
  531 
  532 static void
  533 g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 
  534     struct sbuf *sb, const char *indent)
  535 {
  536         struct g_part_gpt_entry *entry;
  537  
  538         entry = (struct g_part_gpt_entry *)baseentry;
  539         if (indent == NULL) {
  540                 /* conftxt: libdisk compatibility */
  541                 sbuf_printf(sb, " xs GPT xt ");
  542                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
  543         } else if (entry != NULL) {
  544                 /* confxml: partition entry information */
  545                 sbuf_printf(sb, "%s<label>", indent);
  546                 g_gpt_printf_utf16(sb, entry->ent.ent_name,
  547                     sizeof(entry->ent.ent_name) >> 1);
  548                 sbuf_printf(sb, "</label>\n");
  549                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)
  550                         sbuf_printf(sb, "%s<attrib>bootme</attrib>\n", indent);
  551                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) {
  552                         sbuf_printf(sb, "%s<attrib>bootonce</attrib>\n",
  553                             indent);
  554                 }
  555                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) {
  556                         sbuf_printf(sb, "%s<attrib>bootfailed</attrib>\n",
  557                             indent);
  558                 }
  559                 sbuf_printf(sb, "%s<rawtype>", indent);
  560                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
  561                 sbuf_printf(sb, "</rawtype>\n");
  562                 sbuf_printf(sb, "%s<rawuuid>", indent);
  563                 sbuf_printf_uuid(sb, &entry->ent.ent_uuid);
  564                 sbuf_printf(sb, "</rawuuid>\n");
  565         } else {
  566                 /* confxml: scheme information */
  567         }
  568 }
  569 
  570 static int
  571 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
  572 {
  573         struct g_part_gpt_entry *entry;
  574 
  575         entry = (struct g_part_gpt_entry *)baseentry;
  576         return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
  577             EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
  578 }
  579 
  580 static int
  581 g_part_gpt_modify(struct g_part_table *basetable,
  582     struct g_part_entry *baseentry, struct g_part_parms *gpp)
  583 {
  584         struct g_part_gpt_entry *entry;
  585         int error;
  586 
  587         entry = (struct g_part_gpt_entry *)baseentry;
  588         if (gpp->gpp_parms & G_PART_PARM_TYPE) {
  589                 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
  590                 if (error)
  591                         return (error);
  592         }
  593         if (gpp->gpp_parms & G_PART_PARM_LABEL)
  594                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
  595                     sizeof(entry->ent.ent_name) /
  596                     sizeof(entry->ent.ent_name[0]));
  597         return (0);
  598 }
  599 
  600 static int
  601 g_part_gpt_resize(struct g_part_table *basetable,
  602     struct g_part_entry *baseentry, struct g_part_parms *gpp)
  603 {
  604         struct g_part_gpt_entry *entry;
  605         entry = (struct g_part_gpt_entry *)baseentry;
  606 
  607         baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
  608         entry->ent.ent_lba_end = baseentry->gpe_end;
  609 
  610         return (0);
  611 }
  612 
  613 static const char *
  614 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
  615     char *buf, size_t bufsz)
  616 {
  617         struct g_part_gpt_entry *entry;
  618         char c;
  619 
  620         entry = (struct g_part_gpt_entry *)baseentry;
  621         c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
  622         snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
  623         return (buf);
  624 }
  625 
  626 static int
  627 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
  628 {
  629         struct g_provider *pp;
  630         char *buf;
  631         int error, res;
  632 
  633         /* We don't nest, which means that our depth should be 0. */
  634         if (table->gpt_depth != 0)
  635                 return (ENXIO);
  636 
  637         pp = cp->provider;
  638 
  639         /*
  640          * Sanity-check the provider. Since the first sector on the provider
  641          * must be a PMBR and a PMBR is 512 bytes large, the sector size
  642          * must be at least 512 bytes.  Also, since the theoretical minimum
  643          * number of sectors needed by GPT is 6, any medium that has less
  644          * than 6 sectors is never going to be able to hold a GPT. The
  645          * number 6 comes from:
  646          *      1 sector for the PMBR
  647          *      2 sectors for the GPT headers (each 1 sector)
  648          *      2 sectors for the GPT tables (each 1 sector)
  649          *      1 sector for an actual partition
  650          * It's better to catch this pathological case early than behaving
  651          * pathologically later on...
  652          */
  653         if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize)
  654                 return (ENOSPC);
  655 
  656         /* Check that there's a MBR. */
  657         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
  658         if (buf == NULL)
  659                 return (error);
  660         res = le16dec(buf + DOSMAGICOFFSET);
  661         g_free(buf);
  662         if (res != DOSMAGIC) 
  663                 return (ENXIO);
  664 
  665         /* Check that there's a primary header. */
  666         buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
  667         if (buf == NULL)
  668                 return (error);
  669         res = memcmp(buf, GPT_HDR_SIG, 8);
  670         g_free(buf);
  671         if (res == 0)
  672                 return (G_PART_PROBE_PRI_HIGH);
  673 
  674         /* No primary? Check that there's a secondary. */
  675         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
  676             &error);
  677         if (buf == NULL)
  678                 return (error);
  679         res = memcmp(buf, GPT_HDR_SIG, 8); 
  680         g_free(buf);
  681         return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
  682 }
  683 
  684 static int
  685 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
  686 {
  687         struct gpt_hdr *prihdr, *sechdr;
  688         struct gpt_ent *tbl, *pritbl, *sectbl;
  689         struct g_provider *pp;
  690         struct g_part_gpt_table *table;
  691         struct g_part_gpt_entry *entry;
  692         u_char *buf;
  693         uint64_t last;
  694         int error, index;
  695 
  696         table = (struct g_part_gpt_table *)basetable;
  697         pp = cp->provider;
  698         last = (pp->mediasize / pp->sectorsize) - 1;
  699 
  700         /* Read the PMBR */
  701         buf = g_read_data(cp, 0, pp->sectorsize, &error);
  702         if (buf == NULL)
  703                 return (error);
  704         bcopy(buf, table->mbr, MBRSIZE);
  705         g_free(buf);
  706 
  707         /* Read the primary header and table. */
  708         prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
  709         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
  710                 pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
  711         } else {
  712                 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
  713                 pritbl = NULL;
  714         }
  715 
  716         /* Read the secondary header and table. */
  717         sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
  718         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
  719                 sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
  720         } else {
  721                 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
  722                 sectbl = NULL;
  723         }
  724 
  725         /* Fail if we haven't got any good tables at all. */
  726         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
  727             table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
  728                 printf("GEOM: %s: corrupt or invalid GPT detected.\n",
  729                     pp->name);
  730                 printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
  731                     pp->name);
  732                 return (EINVAL);
  733         }
  734 
  735         /*
  736          * If both headers are good but they disagree with each other,
  737          * then invalidate one. We prefer to keep the primary header,
  738          * unless the primary table is corrupt.
  739          */
  740         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
  741             table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
  742             !gpt_matched_hdrs(prihdr, sechdr)) {
  743                 if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
  744                         table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
  745                         table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
  746                         g_free(sechdr);
  747                         sechdr = NULL;
  748                 } else {
  749                         table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
  750                         table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
  751                         g_free(prihdr);
  752                         prihdr = NULL;
  753                 }
  754         }
  755 
  756         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) {
  757                 printf("GEOM: %s: the primary GPT table is corrupt or "
  758                     "invalid.\n", pp->name);
  759                 printf("GEOM: %s: using the secondary instead -- recovery "
  760                     "strongly advised.\n", pp->name);
  761                 table->hdr = sechdr;
  762                 basetable->gpt_corrupt = 1;
  763                 if (prihdr != NULL)
  764                         g_free(prihdr);
  765                 tbl = sectbl;
  766                 if (pritbl != NULL)
  767                         g_free(pritbl);
  768         } else {
  769                 if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
  770                         printf("GEOM: %s: the secondary GPT table is corrupt "
  771                             "or invalid.\n", pp->name);
  772                         printf("GEOM: %s: using the primary only -- recovery "
  773                             "suggested.\n", pp->name);
  774                         basetable->gpt_corrupt = 1;
  775                 } else if (table->lba[GPT_ELT_SECHDR] != last) {
  776                         printf( "GEOM: %s: the secondary GPT header is not in "
  777                             "the last LBA.\n", pp->name);
  778                         basetable->gpt_corrupt = 1;
  779                 }
  780                 table->hdr = prihdr;
  781                 if (sechdr != NULL)
  782                         g_free(sechdr);
  783                 tbl = pritbl;
  784                 if (sectbl != NULL)
  785                         g_free(sectbl);
  786         }
  787 
  788         basetable->gpt_first = table->hdr->hdr_lba_start;
  789         basetable->gpt_last = table->hdr->hdr_lba_end;
  790         basetable->gpt_entries = table->hdr->hdr_entries;
  791 
  792         for (index = basetable->gpt_entries - 1; index >= 0; index--) {
  793                 if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
  794                         continue;
  795                 entry = (struct g_part_gpt_entry *)g_part_new_entry(
  796                     basetable, index + 1, tbl[index].ent_lba_start,
  797                     tbl[index].ent_lba_end);
  798                 entry->ent = tbl[index];
  799         }
  800 
  801         g_free(tbl);
  802         return (0);
  803 }
  804 
  805 static int
  806 g_part_gpt_recover(struct g_part_table *basetable)
  807 {
  808 
  809         g_gpt_set_defaults(basetable,
  810             LIST_FIRST(&basetable->gpt_gp->consumer)->provider);
  811         basetable->gpt_corrupt = 0;
  812         return (0);
  813 }
  814 
  815 static int
  816 g_part_gpt_setunset(struct g_part_table *table, struct g_part_entry *baseentry,
  817     const char *attrib, unsigned int set)
  818 {
  819         struct g_part_entry *iter;
  820         struct g_part_gpt_entry *entry;
  821         int changed, bootme, bootonce, bootfailed;
  822 
  823         bootme = bootonce = bootfailed = 0;
  824         if (strcasecmp(attrib, "bootme") == 0) {
  825                 bootme = 1;
  826         } else if (strcasecmp(attrib, "bootonce") == 0) {
  827                 /* BOOTME is set automatically with BOOTONCE, but not unset. */
  828                 bootonce = 1;
  829                 if (set)
  830                         bootme = 1;
  831         } else if (strcasecmp(attrib, "bootfailed") == 0) {
  832                 /*
  833                  * It should only be possible to unset BOOTFAILED, but it might
  834                  * be useful for test purposes to also be able to set it.
  835                  */
  836                 bootfailed = 1;
  837         }
  838         if (!bootme && !bootonce && !bootfailed)
  839                 return (EINVAL);
  840 
  841         LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) {
  842                 if (iter->gpe_deleted)
  843                         continue;
  844                 if (iter != baseentry)
  845                         continue;
  846                 changed = 0;
  847                 entry = (struct g_part_gpt_entry *)iter;
  848                 if (set) {
  849                         if (bootme &&
  850                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
  851                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTME;
  852                                 changed = 1;
  853                         }
  854                         if (bootonce &&
  855                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
  856                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTONCE;
  857                                 changed = 1;
  858                         }
  859                         if (bootfailed &&
  860                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
  861                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
  862                                 changed = 1;
  863                         }
  864                 } else {
  865                         if (bootme &&
  866                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
  867                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTME;
  868                                 changed = 1;
  869                         }
  870                         if (bootonce &&
  871                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
  872                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
  873                                 changed = 1;
  874                         }
  875                         if (bootfailed &&
  876                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
  877                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTFAILED;
  878                                 changed = 1;
  879                         }
  880                 }
  881                 if (changed && !iter->gpe_created)
  882                         iter->gpe_modified = 1;
  883         }
  884         return (0);
  885 }
  886 
  887 static const char *
  888 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
  889     char *buf, size_t bufsz)
  890 {
  891         struct g_part_gpt_entry *entry;
  892         struct uuid *type;
  893         struct g_part_uuid_alias *uap;
  894  
  895         entry = (struct g_part_gpt_entry *)baseentry;
  896         type = &entry->ent.ent_type;
  897         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++)
  898                 if (EQUUID(type, uap->uuid))
  899                         return (g_part_alias_name(uap->alias));
  900         buf[0] = '!';
  901         snprintf_uuid(buf + 1, bufsz - 1, type);
  902 
  903         return (buf);
  904 }
  905 
  906 static int
  907 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
  908 {
  909         unsigned char *buf, *bp;
  910         struct g_provider *pp;
  911         struct g_part_entry *baseentry;
  912         struct g_part_gpt_entry *entry;
  913         struct g_part_gpt_table *table;
  914         size_t tblsz;
  915         uint32_t crc;
  916         int error, index;
  917 
  918         pp = cp->provider;
  919         table = (struct g_part_gpt_table *)basetable;
  920         tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
  921             pp->sectorsize - 1) / pp->sectorsize;
  922 
  923         /* Write the PMBR */
  924         buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
  925         bcopy(table->mbr, buf, MBRSIZE);
  926         error = g_write_data(cp, 0, buf, pp->sectorsize);
  927         g_free(buf);
  928         if (error)
  929                 return (error);
  930 
  931         /* Allocate space for the header and entries. */
  932         buf = g_malloc((tblsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
  933 
  934         memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
  935         le32enc(buf + 8, table->hdr->hdr_revision);
  936         le32enc(buf + 12, table->hdr->hdr_size);
  937         le64enc(buf + 40, table->hdr->hdr_lba_start);
  938         le64enc(buf + 48, table->hdr->hdr_lba_end);
  939         le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
  940         le32enc(buf + 80, table->hdr->hdr_entries);
  941         le32enc(buf + 84, table->hdr->hdr_entsz);
  942 
  943         LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
  944                 if (baseentry->gpe_deleted)
  945                         continue;
  946                 entry = (struct g_part_gpt_entry *)baseentry;
  947                 index = baseentry->gpe_index - 1;
  948                 bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
  949                 le_uuid_enc(bp, &entry->ent.ent_type);
  950                 le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
  951                 le64enc(bp + 32, entry->ent.ent_lba_start);
  952                 le64enc(bp + 40, entry->ent.ent_lba_end);
  953                 le64enc(bp + 48, entry->ent.ent_attr);
  954                 memcpy(bp + 56, entry->ent.ent_name,
  955                     sizeof(entry->ent.ent_name));
  956         }
  957 
  958         crc = crc32(buf + pp->sectorsize,
  959             table->hdr->hdr_entries * table->hdr->hdr_entsz);
  960         le32enc(buf + 88, crc);
  961 
  962         /* Write primary meta-data. */
  963         le32enc(buf + 16, 0);   /* hdr_crc_self. */
  964         le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_self. */
  965         le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_alt. */
  966         le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);  /* hdr_lba_table. */
  967         crc = crc32(buf, table->hdr->hdr_size);
  968         le32enc(buf + 16, crc);
  969 
  970         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
  971                 error = g_write_data(cp,
  972                     (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
  973                     buf + (index + 1) * pp->sectorsize,
  974                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
  975                     (tblsz - index) * pp->sectorsize);
  976                 if (error)
  977                         goto out;
  978         }
  979         error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
  980             buf, pp->sectorsize);
  981         if (error)
  982                 goto out;
  983 
  984         /* Write secondary meta-data. */
  985         le32enc(buf + 16, 0);   /* hdr_crc_self. */
  986         le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_self. */
  987         le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_alt. */
  988         le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);  /* hdr_lba_table. */
  989         crc = crc32(buf, table->hdr->hdr_size);
  990         le32enc(buf + 16, crc);
  991 
  992         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
  993                 error = g_write_data(cp,
  994                     (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
  995                     buf + (index + 1) * pp->sectorsize,
  996                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
  997                     (tblsz - index) * pp->sectorsize);
  998                 if (error)
  999                         goto out;
 1000         }
 1001         error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
 1002             buf, pp->sectorsize);
 1003 
 1004  out:
 1005         g_free(buf);
 1006         return (error);
 1007 }
 1008 
 1009 static void
 1010 g_gpt_set_defaults(struct g_part_table *basetable, struct g_provider *pp)
 1011 {
 1012         struct g_part_gpt_table *table;
 1013         quad_t last;
 1014         size_t tblsz;
 1015 
 1016         table = (struct g_part_gpt_table *)basetable;
 1017         last = pp->mediasize / pp->sectorsize - 1;
 1018         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
 1019             pp->sectorsize - 1) / pp->sectorsize;
 1020 
 1021         table->lba[GPT_ELT_PRIHDR] = 1;
 1022         table->lba[GPT_ELT_PRITBL] = 2;
 1023         table->lba[GPT_ELT_SECHDR] = last;
 1024         table->lba[GPT_ELT_SECTBL] = last - tblsz;
 1025         table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK;
 1026         table->state[GPT_ELT_PRITBL] = GPT_STATE_OK;
 1027         table->state[GPT_ELT_SECHDR] = GPT_STATE_OK;
 1028         table->state[GPT_ELT_SECTBL] = GPT_STATE_OK;
 1029 
 1030         table->hdr->hdr_lba_start = 2 + tblsz;
 1031         table->hdr->hdr_lba_end = last - tblsz - 1;
 1032 
 1033         basetable->gpt_first = table->hdr->hdr_lba_start;
 1034         basetable->gpt_last = table->hdr->hdr_lba_end;
 1035 }
 1036 
 1037 static void
 1038 g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len)
 1039 {
 1040         u_int bo;
 1041         uint32_t ch;
 1042         uint16_t c;
 1043 
 1044         bo = LITTLE_ENDIAN;     /* GPT is little-endian */
 1045         while (len > 0 && *str != 0) {
 1046                 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
 1047                 str++, len--;
 1048                 if ((ch & 0xf800) == 0xd800) {
 1049                         if (len > 0) {
 1050                                 c = (bo == BIG_ENDIAN) ? be16toh(*str)
 1051                                     : le16toh(*str);
 1052                                 str++, len--;
 1053                         } else
 1054                                 c = 0xfffd;
 1055                         if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
 1056                                 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
 1057                                 ch += 0x10000;
 1058                         } else
 1059                                 ch = 0xfffd;
 1060                 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
 1061                         bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
 1062                         continue;
 1063                 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
 1064                         continue;
 1065 
 1066                 /* Write the Unicode character in UTF-8 */
 1067                 if (ch < 0x80)
 1068                         sbuf_printf(sb, "%c", ch);
 1069                 else if (ch < 0x800)
 1070                         sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
 1071                             0x80 | (ch & 0x3f));
 1072                 else if (ch < 0x10000)
 1073                         sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
 1074                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
 1075                 else if (ch < 0x200000)
 1076                         sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
 1077                             0x80 | ((ch >> 12) & 0x3f),
 1078                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
 1079         }
 1080 }
 1081 
 1082 static void
 1083 g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
 1084 {
 1085         size_t s16idx, s8idx;
 1086         uint32_t utfchar;
 1087         unsigned int c, utfbytes;
 1088 
 1089         s8idx = s16idx = 0;
 1090         utfchar = 0;
 1091         utfbytes = 0;
 1092         bzero(s16, s16len << 1);
 1093         while (s8[s8idx] != 0 && s16idx < s16len) {
 1094                 c = s8[s8idx++];
 1095                 if ((c & 0xc0) != 0x80) {
 1096                         /* Initial characters. */
 1097                         if (utfbytes != 0) {
 1098                                 /* Incomplete encoding of previous char. */
 1099                                 s16[s16idx++] = htole16(0xfffd);
 1100                         }
 1101                         if ((c & 0xf8) == 0xf0) {
 1102                                 utfchar = c & 0x07;
 1103                                 utfbytes = 3;
 1104                         } else if ((c & 0xf0) == 0xe0) {
 1105                                 utfchar = c & 0x0f;
 1106                                 utfbytes = 2;
 1107                         } else if ((c & 0xe0) == 0xc0) {
 1108                                 utfchar = c & 0x1f;
 1109                                 utfbytes = 1;
 1110                         } else {
 1111                                 utfchar = c & 0x7f;
 1112                                 utfbytes = 0;
 1113                         }
 1114                 } else {
 1115                         /* Followup characters. */
 1116                         if (utfbytes > 0) {
 1117                                 utfchar = (utfchar << 6) + (c & 0x3f);
 1118                                 utfbytes--;
 1119                         } else if (utfbytes == 0)
 1120                                 utfbytes = ~0;
 1121                 }
 1122                 /*
 1123                  * Write the complete Unicode character as UTF-16 when we
 1124                  * have all the UTF-8 charactars collected.
 1125                  */
 1126                 if (utfbytes == 0) {
 1127                         /*
 1128                          * If we need to write 2 UTF-16 characters, but
 1129                          * we only have room for 1, then we truncate the
 1130                          * string by writing a 0 instead.
 1131                          */
 1132                         if (utfchar >= 0x10000 && s16idx < s16len - 1) {
 1133                                 s16[s16idx++] =
 1134                                     htole16(0xd800 | ((utfchar >> 10) - 0x40));
 1135                                 s16[s16idx++] =
 1136                                     htole16(0xdc00 | (utfchar & 0x3ff));
 1137                         } else
 1138                                 s16[s16idx++] = (utfchar >= 0x10000) ? 0 :
 1139                                     htole16(utfchar);
 1140                 }
 1141         }
 1142         /*
 1143          * If our input string was truncated, append an invalid encoding
 1144          * character to the output string.
 1145          */
 1146         if (utfbytes != 0 && s16idx < s16len)
 1147                 s16[s16idx++] = htole16(0xfffd);
 1148 }

Cache object: 42d56cd17536942cf82e8d75721ecb2f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.