/* Look up a sector in the VAT */ int udf_vat_map(struct umount *ump, uint32_t *sector) { /* If there's no VAT, then it's easy */ if (!(ump->um_flags & UDF_MNT_USES_VAT)) { *sector += ump->um_start; return (0); } /* Sanity check the given sector */ if (*sector >= ump->um_vat->u_vatlen) return (EINVAL); return (udf_vat_read(ump, sector)); }
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, uint32_t *lb_numres, uint32_t *extres) { struct part_desc *pdesc; struct spare_map_entry *sme; struct long_ad s_icb_loc; uint64_t end_foffset, foffset; int eof, error, flags, part, rel, slot; uint32_t lb_num, lb_packet, lb_rel, lb_size, len; uint32_t ext_offset, udf_rw32_lbmap; uint16_t vpart; KASSERT(ump && icb_loc && lb_numres,("ump && icb_loc && lb_numres")); vpart = le16toh(icb_loc->loc.part_num); lb_num = le32toh(icb_loc->loc.lb_num); if (vpart > UDF_VTOP_RAWPART) return (EINVAL); translate_again: part = ump->vtop[vpart]; pdesc = ump->partitions[part]; switch (ump->vtop_tp[vpart]) { case UDF_VTOP_TYPE_RAW: /* 1:1 to the end of the device */ *lb_numres = lb_num; *extres = INT_MAX; return (0); case UDF_VTOP_TYPE_PHYS: /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* extent from here to the end of the partition */ *extres = le32toh(pdesc->part_len) - lb_num; return (0); case UDF_VTOP_TYPE_VIRT: /* only maps one logical block, lookup in VAT */ if (lb_num >= ump->vat_entries) /* XXX > or >= ? */ return (EINVAL); /* lookup in virtual allocation table file */ error = udf_vat_read(ump, (uint8_t *)&udf_rw32_lbmap, 4, ump->vat_offset + lb_num * 4); if (error != 0) return (error); lb_num = le32toh(udf_rw32_lbmap); /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* just one logical block */ *extres = 1; return (0); case UDF_VTOP_TYPE_SPARABLE: /* check if the packet containing the lb_num is remapped */ lb_packet = lb_num / ump->sparable_packet_size; lb_rel = lb_num % ump->sparable_packet_size; for (rel = 0; rel < le16toh(ump->sparing_table->rt_l); rel++) { sme = &ump->sparing_table->entries[rel]; if (lb_packet == le32toh(sme->org)) { /* NOTE maps to absolute disc logical block! */ *lb_numres = le32toh(sme->map) + lb_rel; *extres = ump->sparable_packet_size - lb_rel; return (0); } } /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* rest of block */ *extres = ump->sparable_packet_size - lb_rel; return (0); case UDF_VTOP_TYPE_META: /* we have to look into the file's allocation descriptors */ /* use metadatafile allocation mutex */ lb_size = le32toh(ump->logical_vol->lb_size); UDF_LOCK_NODE(ump->metadata_node, 0); /* get first overlapping extent */ foffset = 0; slot = 0; for (;;) { udf_get_adslot(ump->metadata_node, slot, &s_icb_loc, &eof); if (eof) { UDF_UNLOCK_NODE(ump->metadata_node, 0); return (EINVAL); } len = le32toh(s_icb_loc.len); flags = UDF_EXT_FLAGS(len); len = UDF_EXT_LEN(len); if (flags == UDF_EXT_REDIRECT) { slot++; continue; } end_foffset = foffset + len; if (end_foffset > lb_num * lb_size) break; /* found */ foffset = end_foffset; slot++; } /* found overlapping slot */ ext_offset = lb_num * lb_size - foffset; /* process extent offset */ lb_num = le32toh(s_icb_loc.loc.lb_num); vpart = le16toh(s_icb_loc.loc.part_num); lb_num += (ext_offset + lb_size -1) / lb_size; ext_offset = 0; UDF_UNLOCK_NODE(ump->metadata_node, 0); if (flags != UDF_EXT_ALLOCATED) return (EINVAL); /* * vpart and lb_num are updated, translate again since we * might be mapped on sparable media */ goto translate_again; default: printf("UDF vtop translation scheme %d unimplemented yet\n", ump->vtop_tp[vpart]); } return (EINVAL); }