From 50c71f25ffe3b8e3ce07a1283b6345b5741ce7b7 Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Wed, 10 Jan 2018 17:58:39 +0100 Subject: libblkid: Support for Atari partitioning scheme Addresses: https://github.com/karelzak/util-linux/issues/517 Signed-off-by: Vaclav Dolezal --- libblkid/src/Makemodule.am | 1 + libblkid/src/partitions/atari.c | 259 +++++++++++++++++++++++++++++++++++ libblkid/src/partitions/partitions.c | 3 +- libblkid/src/partitions/partitions.h | 1 + 4 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 libblkid/src/partitions/atari.c diff --git a/libblkid/src/Makemodule.am b/libblkid/src/Makemodule.am index 1046be100..0e1c765fb 100644 --- a/libblkid/src/Makemodule.am +++ b/libblkid/src/Makemodule.am @@ -29,6 +29,7 @@ libblkid_la_SOURCES = \ \ libblkid/src/partitions/aix.c \ libblkid/src/partitions/aix.h \ + libblkid/src/partitions/atari.c \ libblkid/src/partitions/bsd.c \ libblkid/src/partitions/dos.c \ libblkid/src/partitions/gpt.c \ diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c new file mode 100644 index 000000000..eb3604088 --- /dev/null +++ b/libblkid/src/partitions/atari.c @@ -0,0 +1,259 @@ +/* + * atari partitions parsing code + * + * Copyright (C) 2018 Vaclav Dolezal + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Based on Linux kernel implementation and atari-fdisk + */ + +#include +#include +#include +#include + +#include "partitions.h" + +struct atari_part_def { + /* + * flags: + * 0 (LSB): active + * 1-6: (reserved) + * 7 (MSB): bootable + */ + unsigned char flags; + char id[3]; + uint32_t start; + uint32_t size; +} __attribute__((packed)); + +struct atari_rootsector { + char unused0[0x156]; /* boot code */ + struct atari_part_def icd_part[8]; /* ICD partition entries */ + char unused1[0xc]; + uint32_t hd_size; + struct atari_part_def part[4]; /* primary partition entries */ + uint32_t bsl_start; /* bad sector list start */ + uint32_t bsl_len; /* bad sector list length */ + uint16_t checksum; +} __attribute__((packed)); + + +/* + * Generated using linux kernel ctype.{c,h} + * + * Since kernel uses isalnum() to detect whether it is Atari PT, we need same + * definition of alnum character to be consistent with kernel. + */ +static const unsigned char _linux_isalnum[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, +0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, +0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1 +}; + +static int linux_isalnum(unsigned char c) { + return _linux_isalnum[c]; +} + +#define isalnum linux_isalnum + +#define IS_ACTIVE(partdef) ((partdef).flags & 1) + +#define IS_PARTDEF_VALID(partdef) \ + ( \ + (partdef).flags & 1 && \ + isalnum((partdef).id[0]) && \ + isalnum((partdef).id[1]) && \ + isalnum((partdef).id[2]) \ + ) + +static int is_id_common(char *id) +{ + const char *ids[] = {"GEM", "BGM", "LNX", "SWP", "RAW", }; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (!memcmp(ids[i], id, 3)) + return 1; + } + return 0; +} + +static int parse_partition(blkid_partlist ls, blkid_parttable tab, + struct atari_part_def *part, uint32_t offset) +{ + blkid_partition par; + uint32_t start; + uint32_t size; + + start = be32_to_cpu(part->start) + offset; + size = be32_to_cpu(part->size); + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + return -ENOMEM; + + blkid_partition_set_type_string(par, (unsigned char *) part->id, + sizeof(part->id)); + return 1; +} + +/* + * \return 1: OK, 0: bad format or -errno + */ +static int parse_extended(blkid_probe pr, blkid_partlist ls, + blkid_parttable tab, struct atari_part_def *part) +{ + uint32_t x0start, xstart; + unsigned i = 0; + int rc; + + x0start = xstart = be32_to_cpu(part->start); + while (1) { + struct atari_rootsector *xrs; + xrs = (struct atari_rootsector *) blkid_probe_get_sector(pr, xstart); + if (!rs) { + if (errno) + return -errno; + return 0; + } + + /* + * There must be data partition followed by reference to next + * XGM or inactive entry. + */ + for (i=0; ; i++) { + if (i >= ARRAY_SIZE(xrs->part) - 1) + return 0; + if (IS_ACTIVE(xrs->part[i])) + break; + } + + if (!memcmp(xrs->part[i].id, "XGM", 3)) + return 0; + + rc = parse_partition(ls, tab, &xrs->part[i], xstart); + if (rc < 0) + return rc; + + if (!IS_ACTIVE(xrs->part[i+1])) + break; + + if (memcmp(xrs->part[i+1].id, "XGM", 3)) + return 0; + + xstart = x0start + be32_to_cpu(xrs->part[i+1].start); + } + + return 1; +} + +static int probe_atari_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct atari_rootsector *rs; + + blkid_parttable tab = NULL; + blkid_partlist ls; + + unsigned i; + int has_xgm = 0; + int rc = 0; + + rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0); + if (!rs) { + if (errno) + return -errno; + goto nothing; + } + + /* Look for validly looking primary partition */ + for (i = 0; ; i++) { + if (i >= ARRAY_SIZE(rs->part)) + goto nothing; + + if (IS_PARTDEF_VALID(rs->part[i])) { + blkid_probe_set_magic(pr, + offsetof(struct atari_rootsector, part[i]), + sizeof(rs->part[i].flags) + sizeof(rs->part[i].id), + (unsigned char *) &rs->part[i]); + break; + } + } + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "atari", 0); + if (!tab) + goto err; + + for (i = 0; i < ARRAY_SIZE(rs->part); i++) { + struct atari_part_def *p = &rs->part[i]; + + if (!IS_ACTIVE(*p)) { + blkid_partlist_increment_partno(ls); + continue; + } + + if (!memcmp(p->id, "XGM", 3)) { + has_xgm = 1; + rc = parse_extended(pr, ls, tab, p); + } else { + rc = parse_partition(ls, tab, p, 0); + } + if (rc < 0) + return rc; + } + + /* if there are no XGM partitions, we can try ICD format */ + /* if first ICD partition ID is not valid, assume no ICD format */ + if (!has_xgm && is_id_common(rs->icd_part[0].id)) { + for (i = 0; i < ARRAY_SIZE(rs->icd_part); i++) { + struct atari_part_def *p = &rs->icd_part[i]; + + if (!IS_ACTIVE(*p) || !is_id_common(p->id)) { + blkid_partlist_increment_partno(ls); + continue; + } + + rc = parse_partition(ls, tab, p, 0); + if (rc < 0) + return rc; + } + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +const struct blkid_idinfo atari_pt_idinfo = +{ + .name = "atari", + .probefunc = probe_atari_pt, + .magics = BLKID_NONE_MAGIC +}; diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c index d8fc8e3c8..1f1fc4515 100644 --- a/libblkid/src/partitions/partitions.c +++ b/libblkid/src/partitions/partitions.c @@ -133,7 +133,8 @@ static const struct blkid_idinfo *idinfos[] = &bsd_pt_idinfo, &unixware_pt_idinfo, &solaris_x86_pt_idinfo, - &minix_pt_idinfo + &minix_pt_idinfo, + &atari_pt_idinfo }; /* diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h index 1d99fb6a3..4a718f4ea 100644 --- a/libblkid/src/partitions/partitions.h +++ b/libblkid/src/partitions/partitions.h @@ -69,5 +69,6 @@ extern const struct blkid_idinfo minix_pt_idinfo; extern const struct blkid_idinfo gpt_pt_idinfo; extern const struct blkid_idinfo pmbr_pt_idinfo; extern const struct blkid_idinfo ultrix_pt_idinfo; +extern const struct blkid_idinfo atari_pt_idinfo; #endif /* BLKID_PARTITIONS_H */ -- cgit v1.2.3-55-g7522 From 8326045ace634663af9985aa9940112bcce2270d Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Tue, 23 Jan 2018 16:10:59 +0100 Subject: tests: added test for libblkid atari pt Signed-off-by: Vaclav Dolezal --- tests/expected/blkid/lowprobe-pt-atari-icd | 8 ++++++++ tests/expected/blkid/lowprobe-pt-atari-xgm | 8 ++++++++ tests/ts/blkid/images-pt/atari-icd.img.xz | Bin 0 -> 1920 bytes tests/ts/blkid/images-pt/atari-xgm.img.xz | Bin 0 -> 1920 bytes 4 files changed, 16 insertions(+) create mode 100644 tests/expected/blkid/lowprobe-pt-atari-icd create mode 100644 tests/expected/blkid/lowprobe-pt-atari-xgm create mode 100644 tests/ts/blkid/images-pt/atari-icd.img.xz create mode 100644 tests/ts/blkid/images-pt/atari-xgm.img.xz diff --git a/tests/expected/blkid/lowprobe-pt-atari-icd b/tests/expected/blkid/lowprobe-pt-atari-icd new file mode 100644 index 000000000..29942b123 --- /dev/null +++ b/tests/expected/blkid/lowprobe-pt-atari-icd @@ -0,0 +1,8 @@ +size: 8388608, sector size: 512, PT: atari, offset: 0, id=(null) +--- +#1: 65 4032 0x0 type='FAT' +#2: 4097 904 0x0 type='FOO' +#4: 12289 4096 0x0 type='BAR' +#5: 5002 1999 0x0 type='GEM' +#6: 7003 3238 0x0 type='RAW' +#7: 10241 2048 0x0 type='RAW' diff --git a/tests/expected/blkid/lowprobe-pt-atari-xgm b/tests/expected/blkid/lowprobe-pt-atari-xgm new file mode 100644 index 000000000..4b7756655 --- /dev/null +++ b/tests/expected/blkid/lowprobe-pt-atari-xgm @@ -0,0 +1,8 @@ +size: 8388608, sector size: 512, PT: atari, offset: 0, id=(null) +--- +#1: 65 4032 0x0 type='FAT' +#2: 4097 904 0x0 type='FOO' +#3: 5002 1999 0x0 type='GEM' +#4: 7003 3238 0x0 type='RAW' +#5: 10241 2048 0x0 type='RAW' +#6: 12289 4096 0x0 type='BAR' diff --git a/tests/ts/blkid/images-pt/atari-icd.img.xz b/tests/ts/blkid/images-pt/atari-icd.img.xz new file mode 100644 index 000000000..00a2aba49 Binary files /dev/null and b/tests/ts/blkid/images-pt/atari-icd.img.xz differ diff --git a/tests/ts/blkid/images-pt/atari-xgm.img.xz b/tests/ts/blkid/images-pt/atari-xgm.img.xz new file mode 100644 index 000000000..bc2b8f94a Binary files /dev/null and b/tests/ts/blkid/images-pt/atari-xgm.img.xz differ -- cgit v1.2.3-55-g7522 From 1ca8fba830463e7612d5cf925a8a87515706c024 Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Wed, 24 Jan 2018 12:16:23 +0100 Subject: libblkid: atari - fix bad variable name Signed-off-by: Vaclav Dolezal --- libblkid/src/partitions/atari.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c index eb3604088..1034f8fa4 100644 --- a/libblkid/src/partitions/atari.c +++ b/libblkid/src/partitions/atari.c @@ -127,7 +127,7 @@ static int parse_extended(blkid_probe pr, blkid_partlist ls, while (1) { struct atari_rootsector *xrs; xrs = (struct atari_rootsector *) blkid_probe_get_sector(pr, xstart); - if (!rs) { + if (!xrs) { if (errno) return -errno; return 0; -- cgit v1.2.3-55-g7522 From 8273ef25fa75052fdb71fcd79c94d1fba6d8459d Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Wed, 24 Jan 2018 12:20:11 +0100 Subject: tests: added missing expected outputs for partx (atari) Signed-off-by: Vaclav Dolezal --- tests/expected/partx/partx-image-atari-icd | 7 +++++++ tests/expected/partx/partx-image-atari-xgm | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/expected/partx/partx-image-atari-icd create mode 100644 tests/expected/partx/partx-image-atari-xgm diff --git a/tests/expected/partx/partx-image-atari-icd b/tests/expected/partx/partx-image-atari-icd new file mode 100644 index 000000000..8677dff03 --- /dev/null +++ b/tests/expected/partx/partx-image-atari-icd @@ -0,0 +1,7 @@ +NR START END SECTORS SIZE NAME UUID + 1 65 4096 4032 2M + 2 4097 5000 904 452K + 4 12289 16384 4096 2M + 5 5002 7000 1999 999.5K + 6 7003 10240 3238 1.6M + 7 10241 12288 2048 1M diff --git a/tests/expected/partx/partx-image-atari-xgm b/tests/expected/partx/partx-image-atari-xgm new file mode 100644 index 000000000..248d6a56a --- /dev/null +++ b/tests/expected/partx/partx-image-atari-xgm @@ -0,0 +1,7 @@ +NR START END SECTORS SIZE NAME UUID + 1 65 4096 4032 2M + 2 4097 5000 904 452K + 3 5002 7000 1999 999.5K + 4 7003 10240 3238 1.6M + 5 10241 12288 2048 1M + 6 12289 16384 4096 2M -- cgit v1.2.3-55-g7522 From 98d87b95de6b43cc66e99a4b4013c0d4b5ee40f8 Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Wed, 24 Jan 2018 13:38:14 +0100 Subject: libblkid: atari - test if any partition fits disk size Signed-off-by: Vaclav Dolezal --- libblkid/src/partitions/atari.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c index 1034f8fa4..1ec17d486 100644 --- a/libblkid/src/partitions/atari.c +++ b/libblkid/src/partitions/atari.c @@ -74,12 +74,15 @@ static int linux_isalnum(unsigned char c) { #define IS_ACTIVE(partdef) ((partdef).flags & 1) -#define IS_PARTDEF_VALID(partdef) \ +#define IS_PARTDEF_VALID(partdef, hdsize) \ ( \ (partdef).flags & 1 && \ isalnum((partdef).id[0]) && \ isalnum((partdef).id[1]) && \ - isalnum((partdef).id[2]) \ + isalnum((partdef).id[2]) && \ + be32_to_cpu((partdef).start) <= (hdsize) && \ + be32_to_cpu((partdef).start) + \ + be32_to_cpu((partdef).size) <= (hdsize) \ ) static int is_id_common(char *id) @@ -174,6 +177,7 @@ static int probe_atari_pt(blkid_probe pr, unsigned i; int has_xgm = 0; int rc = 0; + off_t hdsize; rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0); if (!rs) { @@ -182,12 +186,14 @@ static int probe_atari_pt(blkid_probe pr, goto nothing; } + hdsize = blkid_probe_get_size(pr) / 512; + /* Look for validly looking primary partition */ for (i = 0; ; i++) { if (i >= ARRAY_SIZE(rs->part)) goto nothing; - if (IS_PARTDEF_VALID(rs->part[i])) { + if (IS_PARTDEF_VALID(rs->part[i], hdsize)) { blkid_probe_set_magic(pr, offsetof(struct atari_rootsector, part[i]), sizeof(rs->part[i].flags) + sizeof(rs->part[i].id), -- cgit v1.2.3-55-g7522 From 568419b1aa6d3c59c9e55579f18e8c8920337378 Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Wed, 24 Jan 2018 13:52:49 +0100 Subject: libblkid: atari - don't add duplicate entries This should protect against looped XGMs. Signed-off-by: Vaclav Dolezal --- libblkid/src/partitions/atari.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c index 1ec17d486..432df2025 100644 --- a/libblkid/src/partitions/atari.c +++ b/libblkid/src/partitions/atari.c @@ -107,6 +107,13 @@ static int parse_partition(blkid_partlist ls, blkid_parttable tab, start = be32_to_cpu(part->start) + offset; size = be32_to_cpu(part->size); + if (blkid_partlist_get_partition_by_start(ls, start)) { + /* Don't increment partno for extended parts */ + if (!offset) + blkid_partlist_increment_partno(ls); + return 0; + } + par = blkid_partlist_add_partition(ls, tab, start, size); if (!par) return -ENOMEM; @@ -151,7 +158,7 @@ static int parse_extended(blkid_probe pr, blkid_partlist ls, return 0; rc = parse_partition(ls, tab, &xrs->part[i], xstart); - if (rc < 0) + if (rc <= 0) return rc; if (!IS_ACTIVE(xrs->part[i+1])) -- cgit v1.2.3-55-g7522 From 046351760f1a3e739ff20eb3615676cfdff5742d Mon Sep 17 00:00:00 2001 From: Vaclav Dolezal Date: Tue, 30 Jan 2018 13:50:15 +0100 Subject: libblkid: atari - reject devices with blocksize != 512 Signed-off-by: Vaclav Dolezal --- libblkid/src/partitions/atari.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c index 432df2025..1224a577c 100644 --- a/libblkid/src/partitions/atari.c +++ b/libblkid/src/partitions/atari.c @@ -186,6 +186,10 @@ static int probe_atari_pt(blkid_probe pr, int rc = 0; off_t hdsize; + /* Atari partition is not defined for other sector sizes */ + if (blkid_probe_get_sectorsize(pr) != 512) + goto nothing; + rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0); if (!rs) { if (errno) -- cgit v1.2.3-55-g7522