[parted-devel] [PATCH v2] libparted: Add support for MBR id, GPT GUID and detection of UDF filesystem
Pali Rohár
pali.rohar at gmail.com
Fri Sep 28 21:54:18 BST 2018
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
pali.rohar at gmail.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/parted-devel/attachments/20180928/d97a335d/attachment.sig>
More information about the parted-devel
mailing list