+ for (i = j = 0; i + 2 <= in_len; i += 2) {
+ c = (buf[i] << 8) | buf[i+1];
+ if (c == 0) {
+ str[j] = '\0';
+ break;
+ } else if (c < 0x80) {
+ if (j+1 >= out_len)
+ break;
+ str[j++] = (unsigned char) c;
+ } else if (c < 0x800) {
+ if (j+2 >= out_len)
+ break;
+ str[j++] = (unsigned char) (0xc0 | (c >> 6));
+ str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+ } else {
+ if (j+3 >= out_len)
+ break;
+ str[j++] = (unsigned char) (0xe0 | (c >> 12));
+ str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f));
+ str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+ }
+ }
+ str[j] = '\0';
+}
+
+static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)),
+ struct blkid_magic *id __BLKID_ATTR((unused)),
+ unsigned char *buf)
+{
+ struct hfs_mdb *hfs = (struct hfs_mdb *) buf;
+ char uuid_str[17];
+ __u64 uuid;
+
+ if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
+ (memcmp(hfs->embed_sig, "HX", 2) == 0))
+ return 1; /* Not hfs, but an embedded HFS+ */
+
+ uuid = blkid_le64(*((unsigned long long *) hfs->finder_info.id));
+ if (uuid) {
+ sprintf(uuid_str, "%016llX", uuid);
+ blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
+ }
+ blkid_set_tag(probe->dev, "LABEL", hfs->label, hfs->label_len);
+ return 0;
+}
+
+
+static int probe_hfsplus(struct blkid_probe *probe,
+ struct blkid_magic *id,
+ unsigned char *buf)
+{
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ struct hfsplus_bnode_descriptor *descr;
+ struct hfsplus_bheader_record *bnode;
+ struct hfsplus_catalog_key *key;
+ struct hfsplus_vol_header *hfsplus;
+ struct hfs_mdb *sbd = (struct hfs_mdb *) buf;
+ unsigned int alloc_block_size;
+ unsigned int alloc_first_block;
+ unsigned int embed_first_block;
+ unsigned int off = 0;
+ unsigned int blocksize;
+ unsigned int cat_block;
+ unsigned int ext_block_start;
+ unsigned int ext_block_count;
+ unsigned int record_count;
+ unsigned int leaf_node_head;
+ unsigned int leaf_node_count;
+ unsigned int leaf_node_size;
+ unsigned int leaf_block;
+ unsigned int label_len;
+ int ext;
+ __u64 leaf_off, uuid;
+ char uuid_str[17], label[512];
+
+ /* Check for a HFS+ volume embedded in a HFS volume */
+ if (memcmp(sbd->signature, "BD", 2) == 0) {
+ if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
+ (memcmp(sbd->embed_sig, "HX", 2) != 0))
+ /* This must be an HFS volume, so fail */
+ return 1;
+
+ alloc_block_size = blkid_be32(sbd->al_blk_size);
+ alloc_first_block = blkid_be16(sbd->al_bl_st);
+ embed_first_block = blkid_be16(sbd->embed_startblock);
+ off = (alloc_first_block * 512) +
+ (embed_first_block * alloc_block_size);
+ buf = get_buffer(probe, off + (id->bim_kboff * 1024),
+ sizeof(sbd));
+ if (!buf)
+ return 1;
+
+ hfsplus = (struct hfsplus_vol_header *) buf;
+ }
+
+ hfsplus = (struct hfsplus_vol_header *) buf;
+
+ if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
+ (memcmp(hfsplus->signature, "HX", 2) != 0))
+ return 1;
+
+ uuid = blkid_le64(*((unsigned long long *) hfsplus->finder_info.id));
+ if (uuid) {
+ sprintf(uuid_str, "%016llX", uuid);
+ blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
+ }
+
+ blocksize = blkid_be32(hfsplus->blocksize);
+ memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+ cat_block = blkid_be32(extents[0].start_block);
+
+ buf = get_buffer(probe, off + (cat_block * blocksize), 0x2000);
+ if (!buf)
+ return 0;
+
+ bnode = (struct hfsplus_bheader_record *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ leaf_node_head = blkid_be32(bnode->leaf_head);
+ leaf_node_size = blkid_be16(bnode->node_size);
+ leaf_node_count = blkid_be32(bnode->leaf_count);
+ if (leaf_node_count == 0)
+ return 0;
+
+ leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
+
+ /* get physical location */
+ for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
+ ext_block_start = blkid_be32(extents[ext].start_block);
+ ext_block_count = blkid_be32(extents[ext].block_count);
+ if (ext_block_count == 0)
+ return 0;
+
+ /* this is our extent */
+ if (leaf_block < ext_block_count)
+ break;
+
+ leaf_block -= ext_block_count;
+ }
+ if (ext == HFSPLUS_EXTENT_COUNT)
+ return 0;
+
+ leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+ buf = get_buffer(probe, off + leaf_off, leaf_node_size);
+ if (!buf)
+ return 0;
+
+ descr = (struct hfsplus_bnode_descriptor *) buf;
+ record_count = blkid_be16(descr->num_recs);
+ if (record_count == 0)
+ return 0;
+
+ if (descr->type != HFS_NODE_LEAF)
+ return 0;
+
+ key = (struct hfsplus_catalog_key *)
+ &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+ if (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID)
+ return 0;
+
+ label_len = blkid_be16(key->unicode_len) * 2;
+ unicode_16be_to_utf8(label, sizeof(label), key->unicode, label_len);
+ blkid_set_tag(probe->dev, "LABEL", label, 0);
+ return 0;
+}
+
+#define LVM2_LABEL_SIZE 512
+static unsigned int lvm2_calc_crc(const void *buf, unsigned int size)
+{
+ static const unsigned int crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ unsigned int i, crc = 0xf597a6cf;
+ const __u8 *data = (const __u8 *) buf;
+
+ for (i = 0; i < size; i++) {
+ crc ^= *data++;
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+ return crc;
+}
+
+static int probe_lvm2(struct blkid_probe *probe,
+ struct blkid_magic *id,
+ unsigned char *buf)
+{
+ int sector = (id->bim_kboff) << 1;
+ struct lvm2_pv_label_header *label= (struct lvm2_pv_label_header *)buf;
+ char *p, *q, uuid[40];
+ unsigned int i, b;
+
+ /* buf is at 0k or 1k offset; find label inside */
+ if (memcmp(buf, "LABELONE", 8) == 0) {
+ label = (struct lvm2_pv_label_header *)buf;
+ } else if (memcmp(buf + 512, "LABELONE", 8) == 0) {
+ label = (struct lvm2_pv_label_header *)(buf + 512);
+ sector++;
+ } else {
+ return 1;
+ }
+
+ if (blkid_le64(label->sector_xl) != (unsigned) sector) {
+ DBG(DEBUG_PROBE,
+ printf("LVM2: label for sector %llu found at sector %d\n",
+ blkid_le64(label->sector_xl), sector));
+ return 1;
+ }
+
+ if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
+ ((char *)&label->offset_xl - (char *)label)) !=
+ blkid_le32(label->crc_xl)) {
+ DBG(DEBUG_PROBE,
+ printf("LVM2: label checksum incorrect at sector %d\n",
+ sector));
+ return 1;
+ }
+
+ for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i <= 32;
+ i++, b <<= 1) {
+ if (b & 0x4444440)
+ *p++ = '-';
+ *p++ = *q++;
+ }
+
+ blkid_set_tag(probe->dev, "UUID", uuid, LVM2_ID_LEN+6);
+
+ return 0;
+}
+
+static int probe_btrfs(struct blkid_probe *probe,
+ struct blkid_magic *id,
+ unsigned char *buf)
+{
+ struct btrfs_super_block *bs;
+ const char *label = 0;
+
+ bs = (struct btrfs_super_block *)buf;
+
+ if (strlen(bs->label))
+ label = bs->label;
+ blkid_set_tag(probe->dev, "LABEL", label, sizeof(bs->label));
+ set_uuid(probe->dev, bs->fsid, 0);
+ return 0;
+}