]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
udf: support 2048-byte spacing of VRS descriptors on 4K media
authorSteven J. Magnani <steve.magnani@digidescorp.com>
Thu, 11 Jul 2019 13:38:52 +0000 (08:38 -0500)
committerJan Kara <jack@suse.cz>
Wed, 31 Jul 2019 10:04:42 +0000 (12:04 +0200)
Some UDF creators (specifically Microsoft, but perhaps others) mishandle
the ECMA-167 corner case that requires descriptors within a Volume
Recognition Sequence to be placed at 4096-byte intervals on media where
the block size is 4K. Instead, the descriptors are placed at the 2048-
byte interval mandated for media with smaller blocks. This nonconformity
currently prevents Linux from recognizing the filesystem as UDF.

Modify the driver to tolerate a misformatted VRS on 4K media.

[JK: Simplified descriptor checking]
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Tested-by: Steven J. Magnani <steve@digidescorp.com>
Link: https://lore.kernel.org/r/20190711133852.16887-2-steve@digidescorp.com
Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/super.c

index 14a91955507bf7d93a4bd716071c06bf594f95fb..f34e06b4d8fac0ee4614682694681aa6c1ed892a 100644 (file)
@@ -739,6 +739,22 @@ static int udf_check_vsd(struct super_block *sb)
                vsd = (struct volStructDesc *)(bh->b_data +
                                              (sector & (sb->s_blocksize - 1)));
                nsr = identify_vsd(vsd);
+               /* Found NSR or end? */
+               if (nsr) {
+                       brelse(bh);
+                       break;
+               }
+               /*
+                * Special handling for improperly formatted VRS (e.g., Win10)
+                * where components are separated by 2048 bytes even though
+                * sectors are 4K
+                */
+               if (sb->s_blocksize == 4096) {
+                       nsr = identify_vsd(vsd + 1);
+                       /* Ignore unknown IDs... */
+                       if (nsr < 0)
+                               nsr = 0;
+               }
                brelse(bh);
        }