From: Pali Rohár Date: Thu, 5 Nov 2020 18:23:23 +0000 (+0100) Subject: libblkid: udf: add support for multisession via session_offset hint X-Git-Tag: v2.37-rc1~266^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6408acd9e004034cbc193ffd0ca4566be118de0a;p=thirdparty%2Futil-linux.git libblkid: udf: add support for multisession via session_offset hint To read multisession UDF disc it is required to probe VSD and AVDP from the selected session (specified by session_offset) and then read other volume descriptors from absolute location specified in AVDP, which is in most cases in previous session. So it is required for udf detector to be able to read data from any location of disc and therefore blkid's --offset argument cannot be used to access multisession optical disc. Only blkid's --hint session_offset argument can be used to instruct blkid to read multisession optical disc or disc images correctly. Signed-off-by: Pali Rohár --- diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c index 2a36ceadef..97ecdcbe4f 100644 --- a/libblkid/src/superblocks/udf.c +++ b/libblkid/src/superblocks/udf.c @@ -182,6 +182,7 @@ static int probe_udf(blkid_probe pr, struct logical_vol_integ_descriptor_imp_use *lvidiu; uint32_t lvid_len = 0; uint32_t lvid_loc = 0; + uint64_t s_off; uint32_t bs; uint32_t b; uint16_t type; @@ -197,6 +198,10 @@ static int probe_udf(blkid_probe pr, int have_volid = 0; int have_volsetid = 0; + /* Session offset */ + if (blkid_probe_get_hint(pr, "session_offset", &s_off) < 0) + s_off = 0; + /* The block size of a UDF filesystem is that of the underlying * storage; we check later on for the special case of image files, * which may have any block size valid for UDF filesystem */ @@ -208,13 +213,18 @@ static int probe_udf(blkid_probe pr, if (i != 0 && pbs[0] == pbs[i]) continue; + /* Do not try with block size which is not divisor of session offset */ + if (s_off % pbs[i]) + continue; + /* ECMA-167 2/8.4, 2/9.1: Each VSD is either 2048 bytes long or * its size is same as blocksize (for blocksize > 2048 bytes) * plus padded with zeros */ vsd_len = pbs[i] > 2048 ? pbs[i] : 2048; - /* Process 2048 bytes long VSD only once */ - if (vsd_len == 2048) { + /* Process 2048 bytes long VSD on first session only once + * as its location is same for any blocksize */ + if (s_off == 0 && vsd_len == 2048) { if (vsd_2048_valid == 0) continue; if (vsd_2048_valid == 1) @@ -225,7 +235,7 @@ static int probe_udf(blkid_probe pr, for (b = 0; b < 64; b++) { vsd = (struct volume_structure_descriptor *) blkid_probe_get_buffer(pr, - UDF_VSD_OFFSET + b * vsd_len, + s_off + UDF_VSD_OFFSET + b * vsd_len, sizeof(*vsd)); if (!vsd) return errno ? -errno : 1; @@ -249,24 +259,24 @@ static int probe_udf(blkid_probe pr, break; } - if (vsd_len == 2048) + if (s_off == 0 && vsd_len == 2048) vsd_2048_valid = 0; /* NSR was not found, try with next block size */ continue; anchor: - if (vsd_len == 2048) + if (s_off == 0 && vsd_len == 2048) vsd_2048_valid = 1; /* Read Anchor Volume Descriptor (AVDP), detect block size */ vd = (struct volume_descriptor *) - blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd)); + blkid_probe_get_buffer(pr, s_off + 256 * pbs[i], sizeof(*vd)); if (!vd) return errno ? -errno : 1; /* Check that we read correct sector and detected correct block size */ - if (le32_to_cpu(vd->tag.location) != 256) + if (le32_to_cpu(vd->tag.location) != s_off / pbs[i] + 256) continue; type = le16_to_cpu(vd->tag.id); @@ -477,13 +487,13 @@ const struct blkid_idinfo udf_idinfo = .flags = BLKID_IDINFO_TOLERANT, .magics = { - { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, + { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, { NULL } } };