Hi! Can somebody review this second version of UDF patch? On Tuesday 28 August 2018 21:20:01 Pali Rohár wrote: > This is needed for libparted based applications (like Gparted) to correctly > choose MBR id and GPT GUID for UDF filesystem. MBR id for UDF is 0x07 and > GPT GUID is Microsoft Basic Data, see why: https://serverfault.com/a/829172 > > Without registering a new libparted fs code it is not possible to assign > MBR id or GPT GUID. > > Detection of UDF filesystem is done by checking presence of UDF VSD (NSR02 > or NSR03 identifier) and UDF AVDP at expected locations (blocks 256, -257, > -1, 512). > --- > NEWS | 2 + > libparted/fs/Makefile.am | 1 + > libparted/fs/udf/udf.c | 175 > ++++++++++++++++++++++++++++++++++ > libparted/labels/dos.c | 3 + > libparted/labels/gpt.c | 1 + > libparted/libparted.c | 4 + > scripts/data/abi/baseline_symbols.txt | 2 + > tests/Makefile.am | 1 + > tests/t2410-dos-udf-partition-type.sh | 38 ++++++++ > 9 files changed, 227 insertions(+) > create mode 100644 libparted/fs/udf/udf.c > create mode 100644 tests/t2410-dos-udf-partition-type.sh > > diff --git a/NEWS b/NEWS > index ee6efb6..45ea91c 100644 > --- a/NEWS > +++ b/NEWS > @@ -47,6 +47,8 @@ GNU parted NEWS -*- > outline -*- > > ** New Features > > + Add support for MBR id, GPT GUID and detection of UDF filesystem. > + > libparted-fs-resize: Work on non 512 byte sectors. > > Add resizepart command to resize a partition. This works even on > diff --git a/libparted/fs/Makefile.am b/libparted/fs/Makefile.am > index d3cc8bc..cab32c7 100644 > --- a/libparted/fs/Makefile.am > +++ b/libparted/fs/Makefile.am > @@ -44,6 +44,7 @@ libfs_la_SOURCES = \ > ntfs/ntfs.c \ > reiserfs/reiserfs.c \ > reiserfs/reiserfs.h \ > + udf/udf.c \ > ufs/ufs.c \ > xfs/platform_defs.h \ > xfs/xfs.c \ > diff --git a/libparted/fs/udf/udf.c b/libparted/fs/udf/udf.c > new file mode 100644 > index 0000000..00209e1 > --- /dev/null > +++ b/libparted/fs/udf/udf.c > @@ -0,0 +1,175 @@ > +/* > + libparted - a library for manipulating disk partitions > + Copyright (C) 2018 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. > +*/ > + > +#include <config.h> > + > +#include <parted/parted.h> > + > +/* Read bytes using ped_geometry_read() function */ > +static int read_bytes (const PedGeometry* geom, void* buffer, PedSector > offset, PedSector count) > +{ > + char* sector_buffer; > + PedSector sector_offset, sector_count, buffer_offset; > + > + sector_offset = offset / geom->dev->sector_size; > + sector_count = (offset + count + geom->dev->sector_size - 1) / > geom->dev->sector_size - sector_offset; > + buffer_offset = offset - sector_offset * geom->dev->sector_size; > + > + sector_buffer = alloca (sector_count * geom->dev->sector_size); > + > + if (!ped_geometry_read (geom, sector_buffer, sector_offset, > sector_count)) > + return 0; > + > + memcpy (buffer, sector_buffer + buffer_offset, count); > + return 1; > +} > + > +/* Scan VSR and check for UDF VSD */ > +static int check_vrs (const PedGeometry* geom, unsigned int vsdsize) > +{ > + PedSector block; > + PedSector offset; > + unsigned char ident[5]; > + > + /* Check only first 64 blocks, but theoretically standard does not > define upper limit */ > + for (block = 0; block < 64; block++) { > + /* VRS starts at fixed offset 32kB, it is independent of block > size or vsd size */ > + offset = 32768 + block * vsdsize; > + > + /* Read VSD identifier, it is at offset 1 */ > + if (!read_bytes (geom, ident, offset + 1, 5)) > + return 0; > + > + /* Check for UDF identifier */ > + if (memcmp (ident, "NSR02", 5) == 0 || > + memcmp (ident, "NSR03", 5) == 0) > + return 1; > + > + /* Unknown VSD identifier means end of VRS */ > + if (memcmp (ident, "BEA01", 5) != 0 && > + memcmp (ident, "TEA01", 5) != 0 && > + memcmp (ident, "BOOT2", 5) != 0 && > + memcmp (ident, "CD001", 5) != 0 && > + memcmp (ident, "CDW02", 5) != 0) > + break; > + } > + > + return 0; > +} > + > +/* Check for UDF AVDP */ > +static int check_anchor (const PedGeometry* geom, unsigned int blocksize, > int rel_block) > +{ > + PedSector block; > + unsigned char tag[16]; > + > + /* Negative block means relative to the end of device */ > + if (rel_block < 0) { > + block = geom->length * geom->dev->sector_size / blocksize; > + if (block <= (PedSector)(-rel_block)) > + return 0; > + block -= (PedSector)(-rel_block); > + if (block < 257) > + return 0; > + } else { > + block = rel_block; > + } > + > + if (!read_bytes (geom, tag, block * blocksize, 16)) > + return 0; > + > + /* Check for AVDP type (0x0002) */ > + if (((unsigned short)tag[0] | ((unsigned short)tag[1] << 8)) != 0x0002) > + return 0; > + > + /* Check that location stored in AVDP matches */ > + if (((unsigned long)tag[12] | ((unsigned long)tag[13] << 8) | > ((unsigned long)tag[14] << 16) | ((unsigned long)tag[15] << 24)) != block) > + return 0; > + > + return 1; > +} > + > +/* Detect presence of UDF AVDP */ > +static int detect_anchor(const PedGeometry* geom, unsigned int blocksize) > +{ > + /* All possible AVDP locations in preferred order */ > + static int anchors[] = { 256, -257, -1, 512 }; > + size_t i; > + > + for (i = 0; i < sizeof (anchors)/sizeof (*anchors); i++) { > + if (check_anchor (geom, blocksize, anchors[i])) > + return 1; > + } > + > + return 0; > +} > + > +/* Detect UDF filesystem, it must have VRS and AVDP */ > +static int detect_udf (const PedGeometry* geom) > +{ > + unsigned int blocksize; > + > + /* VSD size is min(2048, UDF block size), check for block sizes <= 2048 > */ > + if (check_vrs (geom, 2048)) { > + for (blocksize = 512; blocksize <= 2048; blocksize *= 2) { > + if (detect_anchor (geom, blocksize)) > + return 1; > + } > + } > + > + /* Check for block sizes larger then 2048, maximal theoretical block > size is 32kB */ > + for (blocksize = 4096; blocksize <= 32768; blocksize *= 2) { > + if (!check_vrs (geom, blocksize)) > + continue; > + if (detect_anchor (geom, blocksize)) > + return 1; > + } > + > + return 0; > +} > + > +PedGeometry* > +udf_probe (PedGeometry* geom) > +{ > + if (!detect_udf (geom)) > + return NULL; > + > + return ped_geometry_duplicate (geom); > +} > + > +static PedFileSystemOps udf_ops = { > + probe: udf_probe, > +}; > + > +static PedFileSystemType udf_type = { > + next: NULL, > + ops: &udf_ops, > + name: "udf", > +}; > + > +void > +ped_file_system_udf_init () > +{ > + ped_file_system_type_register (&udf_type); > +} > + > +void > +ped_file_system_udf_done () > +{ > + ped_file_system_type_unregister (&udf_type); > +} > diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c > index fa53020..b2b8de9 100644 > --- a/libparted/labels/dos.c > +++ b/libparted/labels/dos.c > @@ -65,6 +65,7 @@ static const char MBR_BOOT_CODE[] = { > #define PARTITION_FAT16 0x06 > #define PARTITION_NTFS 0x07 > #define PARTITION_HPFS 0x07 > +#define PARTITION_UDF 0x07 > #define PARTITION_FAT32 0x0b > #define PARTITION_FAT32_LBA 0x0c > #define PARTITION_FAT16_LBA 0x0e > @@ -1498,6 +1499,8 @@ msdos_partition_set_system (PedPartition* part, > } else if (!strcmp (fs_type->name, "hfs") > || !strcmp (fs_type->name, "hfs+")) > dos_data->system = PARTITION_HFS; > + else if (!strcmp (fs_type->name, "udf")) > + dos_data->system = PARTITION_UDF; > else if (!strcmp (fs_type->name, "sun-ufs")) > dos_data->system = PARTITION_SUN_UFS; > else if (is_linux_swap (fs_type->name)) > diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c > index 6f92a34..860f415 100644 > --- a/libparted/labels/gpt.c > +++ b/libparted/labels/gpt.c > @@ -1513,6 +1513,7 @@ gpt_partition_set_system (PedPartition *part, > if (fs_type) > { > if (strncmp (fs_type->name, "fat", 3) == 0 > + || strcmp (fs_type->name, "udf") == 0 > || strcmp (fs_type->name, "ntfs") == 0) > { > gpt_part_data->type = PARTITION_BASIC_DATA_GUID; > diff --git a/libparted/libparted.c b/libparted/libparted.c > index 3bd071d..e517875 100644 > --- a/libparted/libparted.c > +++ b/libparted/libparted.c > @@ -112,6 +112,7 @@ extern void ped_file_system_fat_init (void); > extern void ped_file_system_ext2_init (void); > extern void ped_file_system_nilfs2_init (void); > extern void ped_file_system_btrfs_init (void); > +extern void ped_file_system_udf_init (void); > > static void > init_file_system_types () > @@ -128,6 +129,7 @@ init_file_system_types () > ped_file_system_ext2_init (); > ped_file_system_nilfs2_init (); > ped_file_system_btrfs_init (); > + ped_file_system_udf_init (); > } > > extern void ped_disk_aix_done (); > @@ -193,6 +195,7 @@ extern void ped_file_system_ufs_done (void); > extern void ped_file_system_xfs_done (void); > extern void ped_file_system_amiga_done (void); > extern void ped_file_system_btrfs_done (void); > +extern void ped_file_system_udf_done (void); > > static void > done_file_system_types () > @@ -209,6 +212,7 @@ done_file_system_types () > ped_file_system_xfs_done (); > ped_file_system_amiga_done (); > ped_file_system_btrfs_done (); > + ped_file_system_udf_done (); > } > > static void _done() __attribute__ ((destructor)); > diff --git a/scripts/data/abi/baseline_symbols.txt > b/scripts/data/abi/baseline_symbols.txt > index 9162f1a..69abd82 100644 > --- a/scripts/data/abi/baseline_symbols.txt > +++ b/scripts/data/abi/baseline_symbols.txt > @@ -340,6 +340,8 @@ FUNC:ped_file_system_type_get > FUNC:ped_file_system_type_get_next > FUNC:ped_file_system_type_register > FUNC:ped_file_system_type_unregister > +FUNC:ped_file_system_udf_init > +FUNC:ped_file_system_udf_done > FUNC:ped_file_system_ufs_done > FUNC:ped_file_system_ufs_init > FUNC:ped_file_system_xfs_done > diff --git a/tests/Makefile.am b/tests/Makefile.am > index 3851983..3fa75a9 100644 > --- a/tests/Makefile.am > +++ b/tests/Makefile.am > @@ -51,6 +51,7 @@ TESTS = \ > t2310-dos-extended-2-sector-min-offset.sh \ > t2320-dos-extended-noclobber.sh \ > t2400-dos-hfs-partition-type.sh \ > + t2410-dos-udf-partition-type.sh \ > t2500-probe-corrupt-hfs.sh \ > t3000-resize-fs.sh \ > t3200-resize-partition.sh \ > diff --git a/tests/t2410-dos-udf-partition-type.sh > b/tests/t2410-dos-udf-partition-type.sh > new file mode 100644 > index 0000000..7cc8a02 > --- /dev/null > +++ b/tests/t2410-dos-udf-partition-type.sh > @@ -0,0 +1,38 @@ > +#!/bin/sh > +# Ensure that an UDF partition in a dos table gets the right ID > + > +# Copyright (C) 2018 Free Software Foundation, Inc. > + > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 3 of the License, or > +# (at your option) any later version. > + > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > + > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see <http://www.gnu.org/licenses/>. > + > +. "${srcdir=.}/init.sh"; path_prepend_ ../parted > + > +dev=loop-file > +ss=$sector_size_ > +n_sectors=8000 > + > +dd if=/dev/null of=$dev bs=$ss seek=$n_sectors || framework_failure > + > +# create a GPT partition table > +parted -s $dev mklabel msdos \ > + mkpart pri udf 2048s 4095s > out 2>&1 || fail=1 > +# expect no output > +compare /dev/null out || fail=1 > + > +# Extract the "type" byte of the first partition. > +od -An -j450 -tx1 -N1 $dev > out || fail=1 > +printf ' 07\n' > exp || fail=1 > +compare exp out || fail=1 > + > +Exit $fail > -- > 2.11.0 >
-- Pali Rohár [email protected]
signature.asc
Description: PGP signature
