static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag) { struct exfat_super_block *sb; struct exfat_entry_label *label; sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); if (!sb || !CLUSTER_SIZE(sb)) return errno ? -errno : BLKID_PROBE_NONE; label = find_label(pr, sb); if (label) blkid_probe_set_utf8label(pr, label->name, min(label->length * 2, 30), BLKID_ENC_UTF16LE); else if (errno) return -errno; blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4, "%02hhX%02hhX-%02hhX%02hhX", sb->volume_serial[3], sb->volume_serial[2], sb->volume_serial[1], sb->volume_serial[0]); blkid_probe_sprintf_version(pr, "%u.%u", sb->version.vermaj, sb->version.vermin); return BLKID_PROBE_OK; }
static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) { struct nvlist *nvl; struct nvpair *nvp; size_t left = 4096; int found = 0; offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR; /* Note that we currently assume that the desired fields are within * the first 4k (left) of the nvlist. This is true for all pools * I've seen, and simplifies this code somewhat, because we don't * have to handle an nvpair crossing a buffer boundary. */ nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left); if (nvl == NULL) return; nvdebug("zfs_extract: nvlist offset %llu\n", offset); nvp = &nvl->nvl_nvpair; while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) { int avail; /* tracks that name/value data fits in nvp_size */ int namesize; nvp->nvp_size = be32_to_cpu(nvp->nvp_size); nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen); avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp); nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size); if (left < nvp->nvp_size || avail < 0) break; namesize = (nvp->nvp_namelen + 3) & ~3; nvdebug("nvlist: size %u, namelen %u, name %*s\n", nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen, nvp->nvp_name); if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) { struct nvstring *nvs = (void *)(nvp->nvp_name+namesize); nvs->nvs_type = be32_to_cpu(nvs->nvs_type); nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen); if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs)) break; avail -= nvs->nvs_strlen + sizeof(*nvs); nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type, nvs->nvs_strlen, nvs->nvs_string); if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0) blkid_probe_set_label(pr, nvs->nvs_string, nvs->nvs_strlen); found++; } else if (strncmp(nvp->nvp_name, "guid", nvp->nvp_namelen) == 0) { struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); uint64_t nvu_value; memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); nvu->nvu_type = be32_to_cpu(nvu->nvu_type); nvu_value = be64_to_cpu(nvu_value); avail -= sizeof(*nvu); nvdebug("nvuint64: type %u value %"PRIu64"\n", nvu->nvu_type, nvu_value); if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) blkid_probe_sprintf_value(pr, "UUID_SUB", "%"PRIu64, nvu_value); found++; } else if (strncmp(nvp->nvp_name, "pool_guid", nvp->nvp_namelen) == 0) { struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); uint64_t nvu_value; memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); nvu->nvu_type = be32_to_cpu(nvu->nvu_type); nvu_value = be64_to_cpu(nvu_value); avail -= sizeof(*nvu); nvdebug("nvuint64: type %u value %"PRIu64"\n", nvu->nvu_type, nvu_value); if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) blkid_probe_sprintf_uuid(pr, (unsigned char *) &nvu_value, sizeof(nvu_value), "%"PRIu64, nvu_value); found++; } if (left > nvp->nvp_size) left -= nvp->nvp_size; else left = 0; nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size); } }
/* FAT label extraction from the root directory taken from Kay * Sievers's volume_id library */ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) { struct vfat_super_block *vs; struct msdos_super_block *ms; const unsigned char *vol_label = 0; unsigned char *vol_serno = NULL, vol_label_buf[11]; uint16_t sector_size = 0, reserved; uint32_t cluster_count, fat_size; const char *version = NULL; ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); if (!ms) return errno ? -errno : 1; vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); if (!vs) return errno ? -errno : 1; if (!fat_valid_superblock(pr, mag, ms, vs, &cluster_count, &fat_size)) return 1; sector_size = unaligned_le16(&ms->ms_sector_size); reserved = le16_to_cpu(ms->ms_reserved); if (ms->ms_fat_length) { /* the label may be an attribute in the root directory */ uint32_t root_start = (reserved + fat_size) * sector_size; uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries); vol_label = search_fat_label(pr, root_start, root_dir_entries); if (vol_label) { memcpy(vol_label_buf, vol_label, 11); vol_label = vol_label_buf; } if (!vol_label || !memcmp(vol_label, no_name, 11)) vol_label = ms->ms_label; vol_serno = ms->ms_serno; blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos", sizeof("msdos")); if (cluster_count < FAT12_MAX) version = "FAT12"; else if (cluster_count < FAT16_MAX) version = "FAT16"; } else if (vs->vs_fat32_length) { unsigned char *buf; uint16_t fsinfo_sect; int maxloop = 100; /* Search the FAT32 root dir for the label attribute */ uint32_t buf_size = vs->vs_cluster_size * sector_size; uint32_t start_data_sect = reserved + fat_size; uint32_t entries = le32_to_cpu(vs->vs_fat32_length) * sector_size / sizeof(uint32_t); uint32_t next = le32_to_cpu(vs->vs_root_cluster); while (next && next < entries && --maxloop) { uint32_t next_sect_off; uint64_t next_off, fat_entry_off; int count; next_sect_off = (next - 2) * vs->vs_cluster_size; next_off = (uint64_t)(start_data_sect + next_sect_off) * sector_size; count = buf_size / sizeof(struct vfat_dir_entry); vol_label = search_fat_label(pr, next_off, count); if (vol_label) { memcpy(vol_label_buf, vol_label, 11); vol_label = vol_label_buf; break; } /* get FAT entry */ fat_entry_off = ((uint64_t) reserved * sector_size) + (next * sizeof(uint32_t)); buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size); if (buf == NULL) break; /* set next cluster */ next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; } version = "FAT32"; if (!vol_label || !memcmp(vol_label, no_name, 11)) vol_label = vs->vs_label; vol_serno = vs->vs_serno; /* * FAT32 should have a valid signature in the fsinfo block, * but also allow all bytes set to '\0', because some volumes * do not set the signature at all. */ fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector); if (fsinfo_sect) { struct fat32_fsinfo *fsinfo; buf = blkid_probe_get_buffer(pr, (blkid_loff_t) fsinfo_sect * sector_size, sizeof(struct fat32_fsinfo)); if (buf == NULL) return errno ? -errno : 1; fsinfo = (struct fat32_fsinfo *) buf; if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 && memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) return 1; if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) return 1; } } if (vol_label && memcmp(vol_label, no_name, 11)) blkid_probe_set_label(pr, (unsigned char *) vol_label, 11); /* We can't just print them as %04X, because they are unaligned */ if (vol_serno) blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]); if (version) blkid_probe_set_version(pr, version); return 0; }