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 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_romfs(struct volume_id *id /*,uint64_t off*/) { #define off ((uint64_t)0) struct romfs_super *rfs; dbg("probing at offset 0x%llx", (unsigned long long) off); rfs = volume_id_get_buffer(id, off, 0x200); if (rfs == NULL) return -1; if (memcmp(rfs->magic, "-rom1fs-", 4) == 0) { size_t len = strlen((char *)rfs->name); if (len) { // volume_id_set_label_raw(id, rfs->name, len); volume_id_set_label_string(id, rfs->name, len); } // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "romfs"; return 0; } return -1; }
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; }
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_sysv(struct volume_id *id, uint64_t off, uint64_t size) { struct sysv_super *vs; struct xenix_super *xs; unsigned int boff; info("probing at offset 0x%llx", (unsigned long long) off); for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { vs = (struct sysv_super *) volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200); if (vs == NULL) return -1; if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) { volume_id_set_label_raw(id, vs->s_fname, 6); volume_id_set_label_string(id, vs->s_fname, 6); id->type = "sysv"; goto found; } } for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) { xs = (struct xenix_super *) volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200); if (xs == NULL) return -1; if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) { volume_id_set_label_raw(id, xs->s_fname, 6); volume_id_set_label_string(id, xs->s_fname, 6); id->type = "xenix"; goto found; } } return -1; found: volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); return 0; }
int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size) { uint32_t magic; int i; struct ufs_super_block *ufs; int offsets[] = {0, 8, 64, 256, -1}; info("probing at offset 0x%" PRIx64 "\n", off); for (i = 0; offsets[i] >= 0; i++) { ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800); if (ufs == NULL) return -1; dbg("offset 0x%x\n", offsets[i] * 0x400); magic = be32_to_cpu(ufs->fs_magic); if ((magic == UFS_MAGIC) || (magic == UFS2_MAGIC) || (magic == UFS_MAGIC_FEA) || (magic == UFS_MAGIC_LFN)) { dbg("magic 0x%08x(be)\n", magic); goto found; } magic = le32_to_cpu(ufs->fs_magic); if ((magic == UFS_MAGIC) || (magic == UFS2_MAGIC) || (magic == UFS_MAGIC_FEA) || (magic == UFS_MAGIC_LFN)) { dbg("magic 0x%08x(le)\n", magic); goto found; } } return -1; found: volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "ufs"; switch (magic) { case UFS_MAGIC: strcpy(id->type_version, "1"); break; case UFS2_MAGIC: strcpy(id->type_version, "2"); volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32); volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32); break; default: break; } 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 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_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_iso9660(struct volume_id *id, uint64_t off, uint64_t size) { uint8_t *buf; struct iso_volume_descriptor *is; struct high_sierra_volume_descriptor *hs; info("probing at offset 0x%llx", (unsigned long long) off); buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200); if (buf == NULL) return -1; is = (struct iso_volume_descriptor *) buf; if (memcmp(is->id, "CD001", 5) == 0) { int vd_offset; int i; dbg("read label from PVD"); volume_id_set_label_raw(id, is->volume_id, 32); volume_id_set_label_string(id, is->volume_id, 32); dbg("looking for SVDs"); vd_offset = ISO_VD_OFFSET; for (i = 0; i < ISO_VD_MAX; i++) { uint8_t svd_label[64]; is = (struct iso_volume_descriptor *) volume_id_get_buffer(id, off + vd_offset, 0x200); if (is == NULL || is->type == ISO_VD_END) break; if (is->type != ISO_VD_SUPPLEMENTARY) continue; dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset)); if (memcmp(is->escape_sequences, "%/@", 3) == 0|| memcmp(is->escape_sequences, "%/C", 3) == 0|| memcmp(is->escape_sequences, "%/E", 3) == 0) { dbg("Joliet extension found"); volume_id_set_unicode16((char *)svd_label, sizeof(svd_label), is->volume_id, BE, 32); if (memcmp(id->label, svd_label, 16) == 0) { dbg("SVD label is identical, use the possibly longer PVD one"); break; } volume_id_set_label_raw(id, is->volume_id, 32); volume_id_set_label_string(id, svd_label, 32); strcpy(id->type_version, "Joliet Extension"); goto found; } vd_offset += ISO_SECTOR_SIZE; } goto found; } hs = (struct high_sierra_volume_descriptor *) buf; if (memcmp(hs->id, "CDROM", 5) == 0) { strcpy(id->type_version, "High Sierra"); goto found; } return -1; found: volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); id->type = "iso9660"; return 0; }
int FAST_FUNC volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/) { #define off ((uint64_t)0) struct volume_descriptor *vd; struct volume_structure_descriptor *vsd; unsigned bs; unsigned b; unsigned type; unsigned count; unsigned loc; unsigned clen; dbg("probing at offset 0x%llx", (unsigned long long) off); vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200); if (vsd == NULL) return -1; if (memcmp(vsd->id, "NSR02", 5) == 0) goto blocksize; if (memcmp(vsd->id, "NSR03", 5) == 0) goto blocksize; if (memcmp(vsd->id, "BEA01", 5) == 0) goto blocksize; if (memcmp(vsd->id, "BOOT2", 5) == 0) goto blocksize; if (memcmp(vsd->id, "CD001", 5) == 0) goto blocksize; if (memcmp(vsd->id, "CDW02", 5) == 0) goto blocksize; if (memcmp(vsd->id, "TEA03", 5) == 0) goto blocksize; return -1; blocksize: /* search the next VSD to get the logical block size of the volume */ for (bs = 0x800; bs < 0x8000; bs += 0x800) { vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800); if (vsd == NULL) return -1; dbg("test for blocksize: 0x%x", bs); if (vsd->id[0] != '\0') goto nsr; } return -1; nsr: /* search the list of VSDs for a NSR descriptor */ for (b = 0; b < 64; b++) { vsd = volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800); if (vsd == NULL) return -1; dbg("vsd: %c%c%c%c%c", vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]); if (vsd->id[0] == '\0') return -1; if (memcmp(vsd->id, "NSR02", 5) == 0) goto anchor; if (memcmp(vsd->id, "NSR03", 5) == 0) goto anchor; } return -1; anchor: /* read anchor volume descriptor */ vd = volume_id_get_buffer(id, off + (256 * bs), 0x200); if (vd == NULL) return -1; type = le16_to_cpu(vd->tag.id); if (type != 2) /* TAG_ID_AVDP */ goto found; /* get desriptor list address and block count */ count = le32_to_cpu(vd->type.anchor.length) / bs; loc = le32_to_cpu(vd->type.anchor.location); dbg("0x%x descriptors starting at logical secor 0x%x", count, loc); /* pick the primary descriptor from the list */ for (b = 0; b < count; b++) { vd = volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200); if (vd == NULL) return -1; type = le16_to_cpu(vd->tag.id); dbg("descriptor type %i", type); /* check validity */ if (type == 0) goto found; if (le32_to_cpu(vd->tag.location) != loc + b) goto found; if (type == 1) /* TAG_ID_PVD */ goto pvd; } goto found; pvd: // volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32); clen = vd->type.primary.ident.clen; dbg("label string charsize=%i bit", clen); if (clen == 8) volume_id_set_label_string(id, vd->type.primary.ident.c, 31); else if (clen == 16) volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE, 31); found: // volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); // id->type = "udf"; return 0; }