+
+ dir = (struct vfat_dir_entry*) buf;
+
+ for (i = 0; i <= root_dir_entries; i++) {
+ /* end marker */
+ if (dir[i].name[0] == 0x00) {
+ dbg("end of dir");
+ break;
+ }
+
+ /* empty entry */
+ if (dir[i].name[0] == 0xe5)
+ continue;
+
+ if (dir[i].attr == FAT_ATTR_VOLUME) {
+ dbg("found ATTR_VOLUME id in root dir");
+ label = dir[i].name;
+ }
+
+ dbg("skip dir entry");
+ }
+
+ if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
+ set_label_raw(id, label, 11);
+ set_label_string(id, label, 11);
+ } else if (strncmp(vs->type.fat.label, "NO NAME ", 11) != 0) {
+ set_label_raw(id, vs->type.fat.label, 11);
+ set_label_string(id, vs->type.fat.label, 11);
+ }
+ set_uuid(id, vs->type.fat.serno, UUID_DOS);
+ goto found;
+
+fat32:
+ /* FAT32 root dir is a cluster chain like any other directory */
+ buf_size = vs->sectors_per_cluster * sector_size;
+ root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
+ dbg("root dir cluster %u", root_cluster);
+ start_data_sect = reserved + fat_size;
+
+ next = root_cluster;
+ maxloop = 100;
+ while (--maxloop) {
+ __u32 next_sect_off;
+ __u64 next_off;
+ __u64 fat_entry_off;
+ int count;
+
+ dbg("next cluster %u", next);
+ next_sect_off = (next - 2) * vs->sectors_per_cluster;
+ next_off = (start_data_sect + next_sect_off) * sector_size;
+ dbg("cluster offset 0x%llx", next_off);
+
+ /* get cluster */
+ buf = get_buffer(id, off + next_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ dir = (struct vfat_dir_entry*) buf;
+ count = buf_size / sizeof(struct vfat_dir_entry);
+ dbg("expected entries 0x%x", count);
+
+ for (i = 0; i <= count; i++) {
+ /* end marker */
+ if (dir[i].name[0] == 0x00) {
+ dbg("end of dir");
+ goto fat32_label;
+ }
+
+ /* empty entry */
+ if (dir[i].name[0] == 0xe5)
+ continue;
+
+ if (dir[i].attr == FAT_ATTR_VOLUME) {
+ dbg("found ATTR_VOLUME id in root dir");
+ label = dir[i].name;
+ goto fat32_label;
+ }
+
+ dbg("skip dir entry");
+ }
+
+ /* get FAT entry */
+ fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
+ buf = get_buffer(id, off + fat_entry_off, buf_size);
+ if (buf == NULL)
+ goto found;
+
+ /* set next cluster */
+ next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
+ if (next == 0)
+ break;
+ }
+ if (maxloop == 0)
+ dbg("reached maximum follow count of root cluster chain, give up");
+
+fat32_label:
+ if (label != NULL && strncmp(label, "NO NAME ", 11) != 0) {
+ set_label_raw(id, label, 11);
+ set_label_string(id, label, 11);
+ } else if (strncmp(vs->type.fat32.label, "NO NAME ", 11) == 0) {
+ set_label_raw(id, vs->type.fat32.label, 11);
+ set_label_string(id, vs->type.fat32.label, 11);
+ }
+ set_uuid(id, vs->type.fat32.serno, UUID_DOS);
+
+found:
+ id->usage_id = VOLUME_ID_FILESYSTEM;
+ id->type_id = VOLUME_ID_VFAT;
+ id->type = "vfat";
+
+ return 0;
+}
+
+#define UDF_VSD_OFFSET 0x8000
+static int probe_udf(struct volume_id *id, __u64 off)
+{
+ struct volume_descriptor {
+ struct descriptor_tag {
+ __u16 id;
+ __u16 version;
+ __u8 checksum;
+ __u8 reserved;
+ __u16 serial;
+ __u16 crc;
+ __u16 crc_len;
+ __u32 location;
+ } __attribute__((__packed__)) tag;
+ union {
+ struct anchor_descriptor {
+ __u32 length;
+ __u32 location;
+ } __attribute__((__packed__)) anchor;
+ struct primary_descriptor {
+ __u32 seq_num;
+ __u32 desc_num;
+ struct dstring {
+ __u8 clen;
+ __u8 c[31];
+ } __attribute__((__packed__)) ident;
+ } __attribute__((__packed__)) primary;
+ } __attribute__((__packed__)) type;
+ } __attribute__((__packed__)) *vd;
+
+ struct volume_structure_descriptor {
+ __u8 type;
+ __u8 id[5];
+ __u8 version;
+ } *vsd;
+
+ unsigned int bs;
+ unsigned int b;
+ unsigned int type;
+ unsigned int count;
+ unsigned int loc;
+ unsigned int clen;
+
+ vsd = (struct volume_structure_descriptor *)
+ get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
+ if (vsd == NULL)
+ return -1;
+
+ if (strncmp(vsd->id, "NSR02", 5) == 0)
+ goto blocksize;
+ if (strncmp(vsd->id, "NSR03", 5) == 0)
+ goto blocksize;
+ if (strncmp(vsd->id, "BEA01", 5) == 0)
+ goto blocksize;
+ if (strncmp(vsd->id, "BOOT2", 5) == 0)
+ goto blocksize;
+ if (strncmp(vsd->id, "CD001", 5) == 0)
+ goto blocksize;
+ if (strncmp(vsd->id, "CDW02", 5) == 0)
+ goto blocksize;
+ if (strncmp(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 = (struct volume_structure_descriptor *)
+ 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 = (struct volume_structure_descriptor *)
+ 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 (strncmp(vsd->id, "NSR02", 5) == 0)
+ goto anchor;
+ if (strncmp(vsd->id, "NSR03", 5) == 0)
+ goto anchor;
+ }
+ return -1;
+
+anchor:
+ /* read anchor volume descriptor */
+ vd = (struct volume_descriptor *)
+ 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 = (struct volume_descriptor *)
+ 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:
+ 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)
+ set_label_string(id, vd->type.primary.ident.c, 31);
+ else if (clen == 16)
+ set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
+
+found:
+ id->usage_id = VOLUME_ID_FILESYSTEM;
+ id->type_id = VOLUME_ID_UDF;
+ id->type = "udf";
+
+ return 0;
+}
+
+#define ISO_SUPERBLOCK_OFFSET 0x8000
+static int probe_iso9660(struct volume_id *id, __u64 off)
+{
+ union iso_super_block {
+ struct iso_header {
+ __u8 type;
+ __u8 id[5];
+ __u8 version;
+ __u8 unused1;
+ __u8 system_id[32];
+ __u8 volume_id[32];
+ } __attribute__((__packed__)) iso;
+ struct hs_header {
+ __u8 foo[8];
+ __u8 type;
+ __u8 id[4];
+ __u8 version;
+ } __attribute__((__packed__)) hs;
+ } __attribute__((__packed__)) *is;
+
+ is = (union iso_super_block *)
+ get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
+ if (is == NULL)
+ return -1;
+
+ if (strncmp(is->iso.id, "CD001", 5) == 0) {
+ set_label_raw(id, is->iso.volume_id, 32);
+ set_label_string(id, is->iso.volume_id, 32);
+ goto found;
+ }
+ if (strncmp(is->hs.id, "CDROM", 5) == 0)