]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: Support for Atari partitioning scheme
authorVaclav Dolezal <vdolezal@redhat.com>
Wed, 10 Jan 2018 16:58:39 +0000 (17:58 +0100)
committerVaclav Dolezal <vdolezal@redhat.com>
Tue, 23 Jan 2018 16:02:41 +0000 (17:02 +0100)
Addresses: https://github.com/karelzak/util-linux/issues/517
Signed-off-by: Vaclav Dolezal <vdolezal@redhat.com>
libblkid/src/Makemodule.am
libblkid/src/partitions/atari.c [new file with mode: 0644]
libblkid/src/partitions/partitions.c
libblkid/src/partitions/partitions.h

index 1046be10058cae22f0cc1d5a56bd996808c9afb7..0e1c765fb3a72b28ec4ecfd2ff5c647c368a4d85 100644 (file)
@@ -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 (file)
index 0000000..eb36040
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * atari partitions parsing code
+ *
+ * Copyright (C) 2018 Vaclav Dolezal <vdolezal@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Based on Linux kernel implementation and atari-fdisk
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#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
+};
index d8fc8e3c8e402cafc6a5c6d7535550a1aa94a645..1f1fc4515255e4823a77f40e5a065e78483fc436 100644 (file)
@@ -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
 };
 
 /*
index 1d99fb6a36e56f0444ec4d6df9bac9ad9e9d263f..4a718f4eaa42a5183feac84d559d8c8aedb0121e 100644 (file)
@@ -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 */