From f5f269ece5a98f99a52e1dfa5e4d61fee83bf242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 12 Nov 2017 21:55:21 +0100 Subject: [PATCH 1/2] libblkid: udf: Optimize and fix probing when block size > 2048 bytes Optimize probing and detecting for UDF. Do not read and try to detect VRS (Volume Recognition Sequence) on same blocks more times. For specific VSD (Volume Structure Descriptor) length do it only once. Fix probing of devices which has block size larger then 2048 bytes. It is not truth that VSD is always 2048 bytes long. Its size is minimum of the disk block size and 2048 bytes. See ECMA-167 sections 2/8.4 and 2/9.1. Therefore when block size is larger then 2048 bytes, VRS needs to be scanned again. In commit 501aeb60a4914d8e4b273eb1529d70bc6ffaa077 was removed check for empty VSD identifier because it caused that UDF image with block size of the 4096 bytes was not detected. Reason was that VRS was improperly scanned as VSD was 4096 bytes long, with 2048 bytes zero padding. Now when processing of devices with block size larger then 2048 bytes is fixed we can correctly stop scanning VRS at first invalid VSD as specified in ECMA-167 section 2/8.3.1. --- libblkid/src/superblocks/udf.c | 99 +++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 36 deletions(-) diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c index 0c4bca12a..73bf9a8af 100644 --- a/libblkid/src/superblocks/udf.c +++ b/libblkid/src/superblocks/udf.c @@ -167,12 +167,13 @@ static int probe_udf(blkid_probe pr, uint32_t lvid_count = 0; uint32_t lvid_loc = 0; uint32_t bs; - uint32_t pbs[5]; uint32_t b; uint16_t type; uint32_t count; uint32_t loc; size_t i; + uint32_t vsd_len; + int vsd_2048_valid = -1; int have_label = 0; int have_uuid = 0; int have_logvolid = 0; @@ -183,55 +184,81 @@ static int probe_udf(blkid_probe pr, /* 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 */ + uint32_t pbs[] = { 0, 512, 1024, 2048, 4096 }; pbs[0] = blkid_probe_get_sectorsize(pr); - pbs[1] = 512; - pbs[2] = 1024; - pbs[3] = 2048; - pbs[4] = 4096; - /* check for a Volume Structure Descriptor (VSD); each is - * 2048 bytes long */ - for (b = 0; b < 0x8000; b += 0x800) { - vsd = (struct volume_structure_descriptor *) - blkid_probe_get_buffer(pr, - UDF_VSD_OFFSET + b, - sizeof(*vsd)); - if (!vsd) - return errno ? -errno : 1; - if (vsd->id[0] != '\0') - goto nsr; - } - return 1; + for (i = 0; i < ARRAY_SIZE(pbs); i++) { + /* Do not try with block size same as sector size two times */ + if (i != 0 && pbs[0] == pbs[i]) + continue; -nsr: - /* search the list of VSDs for a NSR descriptor */ - for (b = 0; b < 64; b++) { - vsd = (struct volume_structure_descriptor *) - blkid_probe_get_buffer(pr, - UDF_VSD_OFFSET + ((uint64_t) b * 0x800), - sizeof(*vsd)); - if (!vsd) - return errno ? -errno : 1; - if (memcmp(vsd->id, "NSR02", 5) == 0) - goto anchor; - if (memcmp(vsd->id, "NSR03", 5) == 0) - goto anchor; - } - return 1; + /* 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) { + if (vsd_2048_valid == 0) + continue; + else if (vsd_2048_valid == 1) + goto anchor; + } + + /* Check for a Volume Structure Descriptor (VSD) */ + for (b = 0; b < 64; b++) { + vsd = (struct volume_structure_descriptor *) + blkid_probe_get_buffer(pr, + UDF_VSD_OFFSET + b * vsd_len, + sizeof(*vsd)); + if (!vsd) + return errno ? -errno : 1; + if (vsd->id[0] == '\0') + break; + if (memcmp(vsd->id, "NSR02", 5) == 0 || + memcmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + else if (memcmp(vsd->id, "BEA01", 5) != 0 && + memcmp(vsd->id, "BOOT2", 5) != 0 && + memcmp(vsd->id, "CD001", 5) != 0 && + memcmp(vsd->id, "CDW02", 5) != 0 && + memcmp(vsd->id, "TEA01", 5) != 0) + /* ECMA-167 2/8.3.1: The volume recognition sequence is + * terminated by the first sector which is not a valid + * descriptor. + * UDF-2.60 2.1.7: UDF 2.00 and lower revisions do not + * have requirement that NSR descritor is in Extended Area + * (between BEA01 and TEA01) and that there is only one + * Extended Area. So do not stop scanning after TEA01. */ + break; + } + + if (vsd_len == 2048) + vsd_2048_valid = 0; + + /* NSR was not found, try with next block size */ + continue; anchor: - /* read Anchor Volume Descriptor (AVDP), checking block size */ - for (i = 0; i < ARRAY_SIZE(pbs); i++) { + if (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)); 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) + continue; + type = le16_to_cpu(vd->tag.id); if (type == TAG_ID_AVDP) goto real_blksz; + } - return 0; + return 1; real_blksz: /* Use the actual block size from here on out */ From 99777b8d11117b1faab3f00a4c48f77b53c8b475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 12 Nov 2017 22:05:15 +0100 Subject: [PATCH 2/2] test: Add UDF hdd image with final block size 4096 created by Linux mkudffs 1.3 $ dd if=/dev/zero of=udf-hdd-mkudffs-1.3-7.img bs=1M count=10 $ mkudffs -l Label512 -b 512 udf-hdd-mkudffs-1.3-7.img $ mkudffs -l Label4096 -b 4096 udf-hdd-mkudffs-1.3-7.img Image file was first formatted with block size 512 and then reformatted with block size 4096. Volume Recognition Sequence was overwritten and every Volume Structure Descriptor is now 4096 bytes long. Trying to read second VSD as 2048 bytes long will fail because 4069 bytes long VSD is padded with zeros. To verify that image file was properly detected, it should have label "Label4096" and not "Label512". --- .../blkid/low-probe-udf-hdd-mkudffs-1.3-7 | 10 ++++++++++ .../blkid/images-fs/udf-hdd-mkudffs-1.3-7.img.xz | Bin 0 -> 2720 bytes 2 files changed, 10 insertions(+) create mode 100644 tests/expected/blkid/low-probe-udf-hdd-mkudffs-1.3-7 create mode 100644 tests/ts/blkid/images-fs/udf-hdd-mkudffs-1.3-7.img.xz diff --git a/tests/expected/blkid/low-probe-udf-hdd-mkudffs-1.3-7 b/tests/expected/blkid/low-probe-udf-hdd-mkudffs-1.3-7 new file mode 100644 index 000000000..a78606eea --- /dev/null +++ b/tests/expected/blkid/low-probe-udf-hdd-mkudffs-1.3-7 @@ -0,0 +1,10 @@ +ID_FS_LABEL=Label4096 +ID_FS_LABEL_ENC=Label4096 +ID_FS_LOGICAL_VOLUME_ID=Label4096 +ID_FS_TYPE=udf +ID_FS_USAGE=filesystem +ID_FS_UUID=5a08b6f521891529 +ID_FS_UUID_ENC=5a08b6f521891529 +ID_FS_VERSION=2.01 +ID_FS_VOLUME_ID=Label4096 +ID_FS_VOLUME_SET_ID=5a08b6f521891529LinuxUDF diff --git a/tests/ts/blkid/images-fs/udf-hdd-mkudffs-1.3-7.img.xz b/tests/ts/blkid/images-fs/udf-hdd-mkudffs-1.3-7.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..5940009d7bdb4778746044d3e845a96023196cea GIT binary patch literal 2720 zcmeH}c{J1u6vuzeOsQmsNMub@vW+IuV|ZQ|V;TFdM%JN0))pK_p_;O>b>_zf8TTNz3212-|xBG8etAj005pDdWhx)WO*b2 z0D$#6u(;ew$lkL6aABLvrPOl`buc19Ke<{qq{z=u;&yHb13Y*jGFatqU=0&Y| z_Tm$$ba~IyjiyQ`enDvyW<`ZB@QHgeu81sTd@vMUvFscBy1f%!ZT+!D1iVD{WvCnb zJ=ej_5G*N}WC^|TAS1E&2w148CMylWvP1JLO=;|DZQi`)IxHhhP!8NxW?~TQd(j zIZL9Hwq)hnK-paVrs2Yzbb_Eujgw}LcEQS>sxXV2>g*0OJKRU00tLn%K>`Skk@D0v zJ>rq@^%zdaZ-!s1kh_4UeO;|N`;Hw6$$lQOT81)WClK=bwm0gIv zL+(uRMhY9cy?H;vvf%aaD!e~wbvPQ-s1tZ(JTqh=|B4zm=))lZ5|auSQ1H~1w5=0$ zF8eUlU_$O6Yt1teoJj#&AUbRDDQMZ)ZUeH8`(zyjY;N%Az$&AOmA0xMnvQQTooDKT z*EnCI$A{X2giM<(z%C@2+#S&eGg1v3%a?Eu=JVmM6*Y`ooGCE75W-4=4K9VJyp3{yVIO7;M=Vj&4I(MkkJ@?vhsZXRx`x@hI?75 zDw6EE3RNlqKP+sPE z!iw!w@ojkeo6N$+i}(`5s6IkKaEYGc^rA3j#w&zf$R8BCQgNKy}-? zM;WpNeaq+4ha#%M*^hnVahhVg$7j?nWkhAC+9;)j>2WFu%pv&IMGJy literal 0 HcmV?d00001