static int volume_id_probe_linux_raid0(struct volume_id *id, uint64_t off, uint64_t size) { const uint8_t *buf; struct mdp0_super_block *mdp0; union { uint32_t ints[4]; uint8_t bytes[16]; } uuid; info("probing at offset 0x%" PRIx64 ", size 0x%" PRIx64 "\n", off, size); if (size < 0x10000) return -1; buf = volume_id_get_buffer(id, off, 0x800); if (buf == NULL) return -1; mdp0 = (struct mdp0_super_block *) buf; if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { uuid.ints[0] = bswap_32(mdp0->set_uuid0); if (le32_to_cpu(mdp0->minor_version >= 90)) { uuid.ints[1] = bswap_32(mdp0->set_uuid1); uuid.ints[2] = bswap_32(mdp0->set_uuid2); uuid.ints[3] = bswap_32(mdp0->set_uuid3); } else { uuid.ints[1] = 0; uuid.ints[2] = 0; uuid.ints[3] = 0; } volume_id_set_uuid(id, uuid.bytes, 0, UUID_MD); snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u", le32_to_cpu(mdp0->major_version), le32_to_cpu(mdp0->minor_version), le32_to_cpu(mdp0->patch_version)); } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { uuid.ints[0] = mdp0->set_uuid0; if (be32_to_cpu(mdp0->minor_version >= 90)) { uuid.ints[1] = mdp0->set_uuid1; uuid.ints[2] = mdp0->set_uuid2; uuid.ints[3] = mdp0->set_uuid3; } else { uuid.ints[1] = 0; uuid.ints[2] = 0; uuid.ints[3] = 0; } volume_id_set_uuid(id, uuid.bytes, 0, UUID_MD); snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u.%u", be32_to_cpu(mdp0->major_version), be32_to_cpu(mdp0->minor_version), be32_to_cpu(mdp0->patch_version)); } else return -1; volume_id_set_usage(id, VOLUME_ID_RAID); id->type = "linux_raid_member"; return 0; }
int FAST_FUNC volume_id_probe_btrfs(struct volume_id *id /*,uint64_t off*/) { // btrfs has superblocks at 64K, 64M and 256G // minimum btrfs size is 256M // so we never step out the device if we analyze // the first and the second superblocks struct btrfs_super_block *sb; unsigned off = 64; while (off < 64*1024*1024) { off *= 1024; dbg("btrfs: probing at offset 0x%x", off); sb = volume_id_get_buffer(id, off, sizeof(*sb)); if (sb == NULL) return -1; if (memcmp(sb->magic, BTRFS_MAGIC, 8) != 0) return -1; } // N.B.: btrfs natively supports 256 (>VOLUME_ID_LABEL_SIZE) size labels volume_id_set_label_string(id, sb->label, VOLUME_ID_LABEL_SIZE); volume_id_set_uuid(id, sb->fsid, UUID_DCE); return 0; }
int FAST_FUNC volume_id_probe_f2fs(struct volume_id *id /*,uint64_t off*/) { struct f2fs_super_block *sb; // Go for primary super block (ignore second sb) dbg("f2fs: probing at offset 0x%x", F2FS_SB1_OFFSET); sb = volume_id_get_buffer(id, F2FS_SB1_OFFSET, sizeof(*sb)); if (!sb) return -1; if (sb->magic != cpu_to_le32(F2FS_MAGIC)) return -1; IF_FEATURE_BLKID_TYPE(id->type = "f2fs"); // For version 1.0 we don't know sb structure and can't set label/uuid if (sb->major_ver == cpu_to_le16(1) && sb->minor_ver == cpu_to_le16(0)) return 0; volume_id_set_label_unicode16(id, (uint8_t *)sb->volume_name, LE, MIN(F2FS_LABEL_BYTES, VOLUME_ID_LABEL_SIZE)); volume_id_set_uuid(id, sb->uuid, UUID_DCE); return 0; }
static int volume_id_probe_linux_raid1(struct volume_id *id, uint64_t off, uint64_t size) { const uint8_t *buf; struct mdp1_super_block *mdp1; info("probing at offset 0x%" PRIx64 ", size 0x%" PRIx64 "\n", off, size); buf = volume_id_get_buffer(id, off, 0x800); if (buf == NULL) return -1; mdp1 = (struct mdp1_super_block *) buf; if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) return -1; if (le32_to_cpu(mdp1->major_version) != 1) return -1; volume_id_set_uuid(id, mdp1->set_uuid, 0, UUID_MD); volume_id_set_label_raw(id, mdp1->set_name, 32); volume_id_set_label_string(id, mdp1->set_name, 32); volume_id_set_usage(id, VOLUME_ID_RAID); id->type = "linux_raid_member"; return 0; }
int volume_id_probe_ext(struct volume_id *id, uint64_t off) { struct ext2_super_block *es; dbg("ext: probing at offset 0x%llx", (unsigned long long) off); es = volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200); if (es == NULL) return -1; if (es->magic[0] != 0123 || es->magic[1] != 0357) { dbg("ext: no magic found"); return -1; } // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // volume_id_set_label_raw(id, es->volume_name, 16); volume_id_set_label_string(id, es->volume_name, 16); volume_id_set_uuid(id, es->uuid, UUID_DCE); dbg("ext: label '%s' uuid '%s'", id->label, id->uuid); // if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) // id->type = "ext3"; // else // id->type = "ext2"; return 0; }
int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size) { const uint8_t *buf; unsigned int soff; struct lvm2_super_block *lvm; struct lvm2_pv_header *pvhdr; dbg("probing at offset 0x%" PRIx64 "\n", off); buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200); if (buf == NULL) return -1; for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) { lvm = (struct lvm2_super_block *) &buf[soff]; if (memcmp(lvm->id, LVM2_LABEL_ID, 8) == 0) goto found; } return -1; found: dbg("found at offset 0x%x (pv hdr offset 0x%x)\n", soff, cpu_to_le32(lvm->offset_xl)); soff += cpu_to_le32(lvm->offset_xl); pvhdr = (struct lvm2_pv_header *) &buf[soff]; memcpy(id->type_version, lvm->type, 8); volume_id_set_usage(id, VOLUME_ID_RAID); volume_id_set_uuid(id, pvhdr->id, 0, UUID_LVM); id->type = "LVM2_member"; return 0; }
int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/) { struct nilfs2_super_block *sb; // Primary super block dbg("nilfs: probing at offset 0x%x", NILFS_SB1_OFFSET); sb = volume_id_get_buffer(id, NILFS_SB1_OFFSET, sizeof(*sb)); if (sb == NULL) return -1; if (sb->s_magic != NILFS_MAGIC) return -1; // The secondary superblock is not always used, so ignore it for now. // When used it is at 4K from the end of the partition (sb->s_dev_size - NILFS_SB2_OFFSET). volume_id_set_label_string(id, sb->s_volume_name, NILFS_LABEL_SIZE < VOLUME_ID_LABEL_SIZE ? NILFS_LABEL_SIZE : VOLUME_ID_LABEL_SIZE); volume_id_set_uuid(id, sb->s_uuid, UUID_DCE); if (sb->s_rev_level == 2) IF_FEATURE_BLKID_TYPE(id->type = "nilfs2"); return 0; }
int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size) { struct luks_phdr *header; header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE); if (header == NULL) return -1; if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L)) return -1; volume_id_set_usage(id, VOLUME_ID_CRYPTO); volume_id_set_uuid(id, header->uuid, 36, UUID_HEX_STRING); id->type = "crypto_LUKS"; return 0; }
int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/) { #define off ((uint64_t)0) struct swap_header_v1_2 *sw; const uint8_t *buf; unsigned page; dbg("probing at offset 0x%llx", (unsigned long long) off); /* the swap signature is at the end of the PAGE_SIZE */ for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) { buf = volume_id_get_buffer(id, off + page-10, 10); if (buf == NULL) return -1; if (memcmp(buf, "SWAP-SPACE", 10) == 0) { // id->type_version[0] = '1'; // id->type_version[1] = '\0'; goto found; } if (memcmp(buf, "SWAPSPACE2", 10) == 0 || memcmp(buf, "S1SUSPEND", 9) == 0 || memcmp(buf, "S2SUSPEND", 9) == 0 || memcmp(buf, "ULSUSPEND", 9) == 0 ) { sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); if (sw == NULL) return -1; // id->type_version[0] = '2'; // id->type_version[1] = '\0'; // volume_id_set_label_raw(id, sw->volume_name, 16); volume_id_set_label_string(id, sw->volume_name, 16); volume_id_set_uuid(id, sw->uuid, UUID_DCE); goto found; } } return -1; found: // volume_id_set_usage(id, VOLUME_ID_OTHER); // id->type = "swap"; return 0; }
int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/) { #define off ((uint64_t)0) struct luks_phdr *header; header = volume_id_get_buffer(id, off, sizeof(*header)); if (header == NULL) return -1; if (memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L)) return -1; // volume_id_set_usage(id, VOLUME_ID_CRYPTO); volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING); id->type = "crypto_LUKS"; return 0; }
int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size) { struct ext2_super_block *es; size_t bsize; info("probing at offset 0x%llx", (unsigned long long) off); es = (struct ext2_super_block *) volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200); if (es == NULL) return -1; if (es->s_magic != cpu_to_le16(EXT_SUPER_MAGIC)) return -1; bsize = 0x400 << le32_to_cpu(es->s_log_block_size); dbg("ext blocksize 0x%zx", bsize); if (bsize < EXT3_MIN_BLOCK_SIZE || bsize > EXT3_MAX_BLOCK_SIZE) { dbg("invalid ext blocksize"); return -1; } volume_id_set_label_raw(id, es->s_volume_name, 16); volume_id_set_label_string(id, es->s_volume_name, 16); volume_id_set_uuid(id, es->s_uuid, 0, UUID_DCE); snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u", le32_to_cpu(es->s_rev_level), le16_to_cpu(es->s_minor_rev_level)); /* check for external journal device */ if ((le32_to_cpu(es->s_feature_incompat) & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) { volume_id_set_usage(id, VOLUME_ID_OTHER); id->type = "jbd"; return 0; } /* check for ext2 / ext3 */ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); if ((le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) id->type = "ext3"; else id->type = "ext2"; return 0; }
int volume_id_probe_btrfs(struct volume_id *id, uint64_t off, uint64_t size) { const uint8_t *buf; struct btrfs_super_block *bfs; info("probing at offset 0x%" PRIx64 ", size 0x%" PRIx64 "\n", off, size); buf = volume_id_get_buffer(id, off + 0x10000, 0x200); if (buf == NULL) return -1; bfs = (struct btrfs_super_block *)buf; if (memcmp(bfs->magic, "_BHRfS_M", 8) != 0) return -1; volume_id_set_uuid(id, bfs->fsid, 0, UUID_DCE); volume_id_set_uuid_sub(id, bfs->dev_item.uuid, 0, UUID_DCE); volume_id_set_label_raw(id, bfs->label, 256); volume_id_set_label_string(id, bfs->label, 256); volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "btrfs"; return 0; }
int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size) { struct hpfs_super *hs; struct hpfs_spare_super *hss; struct hpfs_boot_block *hbb; uint8_t version; info("probing at offset 0x%" PRIx64 "\n", off); hs = (struct hpfs_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x400); if (hs == NULL) return -1; if (memcmp(hs->magic, "\x49\xe8\x95\xf9", 4) != 0) return -1; hss = (struct hpfs_spare_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_SPARE_OFFSET, 0x200); if (hss == NULL) return -1; if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0) return -1; version = hs->version; /* if boot block looks valid, read label and uuid from there */ hbb = (struct hpfs_boot_block *) volume_id_get_buffer(id, off, 0x200); if (hbb == NULL) return -1; if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 && memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 && hbb->sig_28h == 0x28) { volume_id_set_label_raw(id, hbb->vol_label, 11); volume_id_set_label_string(id, hbb->vol_label, 11); volume_id_set_uuid(id, hbb->vol_serno, 0, UUID_DOS); } sprintf(id->type_version, "%u", version); volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "hpfs"; return 0; }
int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size) { struct jfs_super_block *js; info("probing at offset 0x%" PRIx64 "\n", off); js = (struct jfs_super_block *) volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200); if (js == NULL) return -1; if (memcmp(js->magic, "JFS1", 4) != 0) return -1; volume_id_set_label_raw(id, js->label, 16); volume_id_set_label_string(id, js->label, 16); volume_id_set_uuid(id, js->uuid, 0, UUID_DCE); volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "jfs"; return 0; }
int volume_id_probe_jfs(struct volume_id *id, uint64_t off) { struct jfs_super_block *js; dbg("probing at offset 0x%llx", (unsigned long long) off); js = volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200); if (js == NULL) return -1; if (memcmp(js->magic, "JFS1", 4) != 0) return -1; // volume_id_set_label_raw(id, js->label, 16); volume_id_set_label_string(id, js->label, 16); volume_id_set_uuid(id, js->uuid, UUID_DCE); // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // id->type = "jfs"; return 0; }
int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size) { struct netware_super_block *nw; info("probing at offset 0x%" PRIx64 "\n", off); nw = (struct netware_super_block *) volume_id_get_buffer(id, off + NW_SUPERBLOCK_OFFSET, 0x200); if (nw == NULL) return -1; if (memcmp(nw->SBH_Signature, "SPB5", 4) != 0) return -1; volume_id_set_uuid(id, nw->SBH_PoolID, 0, UUID_DCE); snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%02u", le16_to_cpu(nw->SBH_VersionMediaMajor), le16_to_cpu(nw->SBH_VersionMediaMinor)); volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "nss"; return 0; }
int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off) { struct ocfs2_super_block *os; dbg("probing at offset 0x%llx", (unsigned long long) off); os = volume_id_get_buffer(id, off + OCFS2_SUPERBLOCK_OFFSET, 0x200); if (os == NULL) return -1; if (memcmp(os->i_signature, "OCFSV2", 6) != 0) { return -1; } // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // volume_id_set_label_raw(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? // OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); volume_id_set_uuid(id, os->s_uuid, UUID_DCE); // id->type = "ocfs2"; return 0; }
int FAST_FUNC volume_id_probe_vfat(struct volume_id *id /*,uint64_t fat_partition_off*/) { #define fat_partition_off ((uint64_t)0) struct vfat_super_block *vs; struct vfat_dir_entry *dir; uint16_t sector_size_bytes; uint16_t dir_entries; uint32_t sect_count; uint16_t reserved_sct; uint32_t fat_size_sct; uint32_t root_cluster; uint32_t dir_size_sct; uint32_t cluster_count; uint64_t root_start_off; uint32_t start_data_sct; uint8_t *buf; uint32_t buf_size; uint8_t *label = NULL; uint32_t next_cluster; int maxloop; dbg("probing at offset 0x%llx", (unsigned long long) fat_partition_off); vs = volume_id_get_buffer(id, fat_partition_off, 0x200); if (vs == NULL) return -1; /* believe only that's fat, don't trust the version * the cluster_count will tell us */ if (memcmp(vs->sysid, "NTFS", 4) == 0) return -1; if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0) goto valid; if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0) goto valid; if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0) goto valid; if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0) goto valid; if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0) goto valid; /* * There are old floppies out there without a magic, so we check * for well known values and guess if it's a fat volume */ /* boot jump address check */ if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && vs->boot_jump[0] != 0xe9 ) { return -1; } /* heads check */ if (vs->heads == 0) return -1; /* cluster size check */ if (vs->sectors_per_cluster == 0 || (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)) ) { return -1; } /* media check */ if (vs->media < 0xf8 && vs->media != 0xf0) return -1; /* fat count*/ if (vs->fats != 2) return -1; valid: /* sector size check */ sector_size_bytes = le16_to_cpu(vs->sector_size_bytes); if (sector_size_bytes != 0x200 && sector_size_bytes != 0x400 && sector_size_bytes != 0x800 && sector_size_bytes != 0x1000 ) { return -1; } dbg("sector_size_bytes 0x%x", sector_size_bytes); dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); reserved_sct = le16_to_cpu(vs->reserved_sct); dbg("reserved_sct 0x%x", reserved_sct); sect_count = le16_to_cpu(vs->sectors); if (sect_count == 0) sect_count = le32_to_cpu(vs->total_sect); dbg("sect_count 0x%x", sect_count); fat_size_sct = le16_to_cpu(vs->fat_length); if (fat_size_sct == 0) fat_size_sct = le32_to_cpu(vs->type.fat32.fat32_length); fat_size_sct *= vs->fats; dbg("fat_size_sct 0x%x", fat_size_sct); dir_entries = le16_to_cpu(vs->dir_entries); dir_size_sct = ((dir_entries * sizeof(struct vfat_dir_entry)) + (sector_size_bytes-1)) / sector_size_bytes; dbg("dir_size_sct 0x%x", dir_size_sct); cluster_count = sect_count - (reserved_sct + fat_size_sct + dir_size_sct); cluster_count /= vs->sectors_per_cluster; dbg("cluster_count 0x%x", cluster_count); // if (cluster_count < FAT12_MAX) { // strcpy(id->type_version, "FAT12"); // } else if (cluster_count < FAT16_MAX) { // strcpy(id->type_version, "FAT16"); // } else { // strcpy(id->type_version, "FAT32"); // goto fat32; // } if (cluster_count >= FAT16_MAX) goto fat32; /* the label may be an attribute in the root directory */ root_start_off = (reserved_sct + fat_size_sct) * sector_size_bytes; dbg("root dir start 0x%llx", (unsigned long long) root_start_off); dbg("expected entries 0x%x", dir_entries); buf_size = dir_entries * sizeof(struct vfat_dir_entry); buf = volume_id_get_buffer(id, fat_partition_off + root_start_off, buf_size); if (buf == NULL) goto ret; label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries); vs = volume_id_get_buffer(id, fat_partition_off, 0x200); if (vs == NULL) return -1; if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { // volume_id_set_label_raw(id, label, 11); volume_id_set_label_string(id, label, 11); } else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) { // volume_id_set_label_raw(id, vs->type.fat.label, 11); volume_id_set_label_string(id, vs->type.fat.label, 11); } volume_id_set_uuid(id, vs->type.fat.serno, UUID_DOS); goto ret; fat32: /* FAT32 root dir is a cluster chain like any other directory */ buf_size = vs->sectors_per_cluster * sector_size_bytes; root_cluster = le32_to_cpu(vs->type.fat32.root_cluster); start_data_sct = reserved_sct + fat_size_sct; next_cluster = root_cluster; maxloop = 100; while (--maxloop) { uint64_t next_off_sct; uint64_t next_off; uint64_t fat_entry_off; int count; dbg("next_cluster 0x%x", (unsigned)next_cluster); next_off_sct = (uint64_t)(next_cluster - 2) * vs->sectors_per_cluster; next_off = (start_data_sct + next_off_sct) * sector_size_bytes; dbg("cluster offset 0x%llx", (unsigned long long) next_off); /* get cluster */ buf = volume_id_get_buffer(id, fat_partition_off + next_off, buf_size); if (buf == NULL) goto ret; dir = (struct vfat_dir_entry*) buf; count = buf_size / sizeof(struct vfat_dir_entry); dbg("expected entries 0x%x", count); label = get_attr_volume_id(dir, count); if (label) break; /* get FAT entry */ fat_entry_off = (reserved_sct * sector_size_bytes) + (next_cluster * sizeof(uint32_t)); dbg("fat_entry_off 0x%llx", (unsigned long long)fat_entry_off); buf = volume_id_get_buffer(id, fat_partition_off + fat_entry_off, buf_size); if (buf == NULL) goto ret; /* set next cluster */ next_cluster = le32_to_cpu(*(uint32_t*)buf) & 0x0fffffff; if (next_cluster < 2 || next_cluster > FAT32_MAX) break; } if (maxloop == 0) dbg("reached maximum follow count of root cluster chain, give up"); vs = volume_id_get_buffer(id, fat_partition_off, 0x200); if (vs == NULL) return -1; if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) { // volume_id_set_label_raw(id, label, 11); volume_id_set_label_string(id, label, 11); } else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) { // volume_id_set_label_raw(id, vs->type.fat32.label, 11); volume_id_set_label_string(id, vs->type.fat32.label, 11); } volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS); ret: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // id->type = "vfat"; return 0; }
int volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/) { #define off ((uint64_t)0) unsigned sector_size; unsigned cluster_size; uint64_t mft_cluster; uint64_t mft_off; unsigned mft_record_size; unsigned attr_type; unsigned attr_off; unsigned attr_len; unsigned val_off; unsigned val_len; struct master_file_table_record *mftr; struct ntfs_super_block *ns; const uint8_t *buf; const uint8_t *val; dbg("probing at offset 0x%llx", (unsigned long long) off); ns = volume_id_get_buffer(id, off, 0x200); if (ns == NULL) return -1; if (memcmp(ns->oem_id, "NTFS", 4) != 0) return -1; volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS); sector_size = le16_to_cpu(ns->bytes_per_sector); cluster_size = ns->sectors_per_cluster * sector_size; mft_cluster = le64_to_cpu(ns->mft_cluster_location); mft_off = mft_cluster * cluster_size; if (ns->cluster_per_mft_record < 0) /* size = -log2(mft_record_size); normally 1024 Bytes */ mft_record_size = 1 << -ns->cluster_per_mft_record; else mft_record_size = ns->cluster_per_mft_record * cluster_size; dbg("sectorsize 0x%x", sector_size); dbg("clustersize 0x%x", cluster_size); dbg("mftcluster %llu", (unsigned long long) mft_cluster); dbg("mftoffset 0x%llx", (unsigned long long) mft_off); dbg("cluster per mft_record %i", ns->cluster_per_mft_record); dbg("mft record size %i", mft_record_size); buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size), mft_record_size); if (buf == NULL) goto found; mftr = (struct master_file_table_record*) buf; dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]); if (memcmp(mftr->magic, "FILE", 4) != 0) goto found; attr_off = le16_to_cpu(mftr->attrs_offset); dbg("file $Volume's attributes are at offset %i", attr_off); while (1) { struct file_attribute *attr; attr = (struct file_attribute*) &buf[attr_off]; attr_type = le32_to_cpu(attr->type); attr_len = le16_to_cpu(attr->len); val_off = le16_to_cpu(attr->value_offset); val_len = le32_to_cpu(attr->value_len); attr_off += attr_len; if (attr_len == 0) break; if (attr_off >= mft_record_size) break; if (attr_type == MFT_RECORD_ATTR_END) break; dbg("found attribute type 0x%x, len %i, at offset %i", attr_type, attr_len, attr_off); // if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) { // struct volume_info *info; // dbg("found info, len %i", val_len); // info = (struct volume_info*) (((uint8_t *) attr) + val_off); // snprintf(id->type_version, sizeof(id->type_version)-1, // "%u.%u", info->major_ver, info->minor_ver); // } if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { dbg("found label, len %i", val_len); if (val_len > VOLUME_ID_LABEL_SIZE) val_len = VOLUME_ID_LABEL_SIZE; val = ((uint8_t *) attr) + val_off; // volume_id_set_label_raw(id, val, val_len); volume_id_set_label_unicode16(id, val, LE, val_len); } } found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // id->type = "ntfs"; return 0; }
int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size) { unsigned int sector_size; unsigned int cluster_size; uint64_t mft_cluster; uint64_t mft_off; unsigned int mft_record_size; unsigned int attr_type; unsigned int attr_off; unsigned int attr_len; unsigned int val_off; unsigned int val_len; const uint8_t *buf; const uint8_t *val; info("probing at offset 0x%" PRIx64 "\n", off); ns = (struct ntfs_super_block *) volume_id_get_buffer(id, off, 0x200); if (ns == NULL) return -1; if (memcmp(ns->oem_id, "NTFS", 4) != 0) return -1; volume_id_set_uuid(id, ns->volume_serial, 0, UUID_64BIT_LE); sector_size = le16_to_cpu(ns->bytes_per_sector); if (sector_size < 0x200) return -1; cluster_size = ns->sectors_per_cluster * sector_size; mft_cluster = le64_to_cpu(ns->mft_cluster_location); mft_off = mft_cluster * cluster_size; if (ns->cluster_per_mft_record < 0) /* size = -log2(mft_record_size); normally 1024 Bytes */ mft_record_size = 1 << -ns->cluster_per_mft_record; else mft_record_size = ns->cluster_per_mft_record * cluster_size; dbg("sectorsize 0x%x\n", sector_size); dbg("clustersize 0x%x\n", cluster_size); dbg("mftcluster %" PRIu64 "\n", mft_cluster); dbg("mftoffset 0x%" PRIx64 "\n", mft_off); dbg("cluster per mft_record %i\n", ns->cluster_per_mft_record); dbg("mft record size %i\n", mft_record_size); buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size), mft_record_size); if (buf == NULL) return -1; mftr = (struct master_file_table_record*) buf; dbg("mftr->magic '%c%c%c%c'\n", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]); if (memcmp(mftr->magic, "FILE", 4) != 0) return -1; attr_off = le16_to_cpu(mftr->attrs_offset); dbg("file $Volume's attributes are at offset %i\n", attr_off); while (1) { attr = (struct file_attribute*) &buf[attr_off]; attr_type = le32_to_cpu(attr->type); attr_len = le16_to_cpu(attr->len); val_off = le16_to_cpu(attr->value_offset); val_len = le32_to_cpu(attr->value_len); attr_off += attr_len; if (attr_len == 0) break; if (attr_off >= mft_record_size) break; if (attr_type == MFT_RECORD_ATTR_END) break; dbg("found attribute type 0x%x, len %i, at offset %i\n", attr_type, attr_len, attr_off); if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) { dbg("found info, len %i\n", val_len); info = (struct volume_info*) (((uint8_t *) attr) + val_off); snprintf(id->type_version, sizeof(id->type_version)-1, "%u.%u", info->major_ver, info->minor_ver); } if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { dbg("found label, len %i\n", val_len); if (val_len > VOLUME_ID_LABEL_SIZE) val_len = VOLUME_ID_LABEL_SIZE; val = ((uint8_t *) attr) + val_off; volume_id_set_label_raw(id, val, val_len); volume_id_set_label_unicode16(id, val, LE, val_len); } } volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "ntfs"; /* we think this is ntfs, but we make sure no other signatures are found */ id->force_unique_result = 1; return 0; }