Coverage Report

Created: 2026-03-10 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/partitions/atari.c
Line
Count
Source
1
/*
2
 * atari partitions parsing code
3
 *
4
 * Copyright (C) 2018 Vaclav Dolezal <vdolezal@redhat.com>
5
 *
6
 * This file may be redistributed under the terms of the
7
 * GNU Lesser General Public License.
8
 *
9
 * Based on Linux kernel implementation and atari-fdisk
10
 */
11
12
#include <stdio.h>
13
#include <string.h>
14
#include <stdlib.h>
15
#include <stdint.h>
16
17
#include "partitions.h"
18
19
struct atari_part_def {
20
  /*
21
   * flags:
22
   * 0 (LSB): active
23
   * 1-6:     (reserved)
24
   * 7 (MSB): bootable
25
   */
26
  unsigned char flags;
27
  char id[3];
28
  uint32_t start;
29
  uint32_t size;
30
} __attribute__((packed));
31
32
struct atari_rootsector {
33
  char unused0[0x156]; /* boot code */
34
  struct atari_part_def icd_part[8]; /* ICD partition entries */
35
  char unused1[0xc];
36
  uint32_t hd_size;
37
  struct atari_part_def part[4]; /* primary partition entries */
38
  uint32_t bsl_start; /* bad sector list start */
39
  uint32_t bsl_len; /* bad sector list length */
40
  uint16_t checksum;
41
} __attribute__((packed));
42
43
44
/*
45
 * Generated using linux kernel ctype.{c,h}
46
 *
47
 * Since kernel uses isalnum() to detect whether it is Atari PT, we need same
48
 * definition of alnum character to be consistent with kernel.
49
 */
50
static const unsigned char _linux_isalnum[] = {
51
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
52
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
53
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
54
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
55
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
56
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
57
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
58
1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
59
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
60
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
61
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
62
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
63
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
64
1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
65
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
66
1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1
67
};
68
69
static int linux_isalnum(unsigned char c)
70
1.51k
{
71
1.51k
  return _linux_isalnum[c];
72
1.51k
}
73
74
1.51k
#define isalnum linux_isalnum
75
76
0
#define IS_ACTIVE(partdef) ((partdef).flags & 1)
77
78
static int is_valid_dimension(uint32_t start, uint32_t size, uint32_t maxoff)
79
1.22k
{
80
1.22k
  uint64_t end = start + size;
81
82
1.22k
  return  end >= start
83
896
    && 0 < start && start <= maxoff
84
361
    && 0 < size && size <= maxoff
85
164
    && 0 < end && end <= maxoff;
86
1.22k
}
87
88
static int is_valid_partition(struct atari_part_def *part, uint32_t maxoff)
89
1.19k
{
90
1.19k
  uint32_t start = be32_to_cpu(part->start),
91
1.19k
     size = be32_to_cpu(part->size);
92
93
1.19k
  return (part->flags & 1)
94
604
    && isalnum(part->id[0])
95
486
    && isalnum(part->id[1])
96
429
    && isalnum(part->id[2])
97
390
    && is_valid_dimension(start, size, maxoff);
98
1.19k
}
99
100
static int is_id_common(char *id)
101
0
{
102
0
  const char *ids[] = {"GEM", "BGM", "LNX", "SWP", "RAW", };
103
0
  unsigned i;
104
105
0
  for (i = 0; i < ARRAY_SIZE(ids); i++) {
106
0
    if (!memcmp(ids[i], id, 3))
107
0
      return 1;
108
0
  }
109
0
  return 0;
110
0
}
111
112
static int parse_partition(blkid_partlist ls, blkid_parttable tab,
113
  struct atari_part_def *part, uint32_t offset)
114
0
{
115
0
  blkid_partition par;
116
0
  uint32_t start;
117
0
  uint32_t size;
118
119
0
  start = be32_to_cpu(part->start) + offset;
120
0
  size = be32_to_cpu(part->size);
121
122
0
  if (blkid_partlist_get_partition_by_start(ls, start)) {
123
    /* Don't increment partno for extended parts */
124
0
    if (!offset)
125
0
      blkid_partlist_increment_partno(ls);
126
0
    return 0;
127
0
  }
128
129
0
  par = blkid_partlist_add_partition(ls, tab, start, size);
130
0
  if (!par)
131
0
    return -ENOMEM;
132
133
0
  blkid_partition_set_type_string(par, (unsigned char *) part->id,
134
0
          sizeof(part->id));
135
0
  return 1;
136
0
}
137
138
/*
139
 * \return 1: OK, 0: bad format or -errno
140
 */
141
static int parse_extended(blkid_probe pr, blkid_partlist ls,
142
  blkid_parttable tab, struct atari_part_def *part)
143
0
{
144
0
  uint32_t x0start, xstart;
145
0
  unsigned ct = 0, i = 0;
146
0
  int rc;
147
148
0
  x0start = xstart = be32_to_cpu(part->start);
149
0
  while (1) {
150
0
    struct atari_rootsector *xrs;
151
152
0
    if (++ct > 100)
153
0
      break;
154
155
0
    xrs = (struct atari_rootsector *) blkid_probe_get_sector(pr, xstart);
156
0
    if (!xrs) {
157
0
      if (errno)
158
0
        return -errno;
159
0
      return 0;
160
0
    }
161
162
    /*
163
     * There must be data partition followed by reference to next
164
     * XGM or inactive entry.
165
     */
166
0
    for (i=0; ; i++) {
167
0
      if (i >= ARRAY_SIZE(xrs->part) - 1)
168
0
        return 0;
169
0
      if (IS_ACTIVE(xrs->part[i]))
170
0
        break;
171
0
    }
172
173
0
    if (!memcmp(xrs->part[i].id, "XGM", 3))
174
0
      return 0;
175
176
0
    rc = parse_partition(ls, tab, &xrs->part[i], xstart);
177
0
    if (rc <= 0)
178
0
      return rc;
179
180
0
    if (!IS_ACTIVE(xrs->part[i+1]))
181
0
      break;
182
183
0
    if (memcmp(xrs->part[i+1].id, "XGM", 3) != 0)
184
0
      return 0;
185
186
0
    xstart = x0start + be32_to_cpu(xrs->part[i+1].start);
187
0
  }
188
189
0
  return 1;
190
0
}
191
192
static int probe_atari_pt(blkid_probe pr,
193
    const struct blkid_idmag *mag __attribute__((__unused__)))
194
4.79k
{
195
4.79k
  struct atari_rootsector *rs;
196
197
4.79k
  blkid_parttable tab = NULL;
198
4.79k
  blkid_partlist ls;
199
200
4.79k
  unsigned i;
201
4.79k
  int has_xgm = 0;
202
4.79k
  int rc = 0;
203
4.79k
  uint32_t rssize;  /* size in sectors from root sector */
204
4.79k
  uint64_t size;    /* size in sectors from system */
205
206
  /* Atari partition is not defined for other sector sizes */
207
4.79k
  if (blkid_probe_get_sectorsize(pr) != 512)
208
0
    goto nothing;
209
210
4.79k
  size = blkid_probe_get_size(pr) / 512;
211
212
  /* Atari is not well defined to support large disks */
213
4.79k
  if (size > INT32_MAX)
214
0
    goto nothing;
215
216
  /* read root sector */
217
4.79k
  rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0);
218
4.79k
  if (!rs) {
219
0
    if (errno)
220
0
      return -errno;
221
0
    goto nothing;
222
0
  }
223
224
4.79k
  rssize = be32_to_cpu(rs->hd_size);
225
226
  /* check number of sectors stored in the root sector */
227
4.79k
  if (rssize < 2 || rssize > size)
228
3.76k
    goto nothing;
229
230
  /* check list of bad blocks */
231
1.02k
  if ((rs->bsl_start || rs->bsl_len)
232
833
      && !is_valid_dimension(be32_to_cpu(rs->bsl_start),
233
833
           be32_to_cpu(rs->bsl_len),
234
833
           rssize))
235
729
    goto nothing;
236
237
  /*
238
   * At least one valid partition required
239
   */
240
1.49k
  for (i = 0; i < 4; i++) {
241
1.19k
    if (is_valid_partition(&rs->part[i], rssize)) {
242
5
      if (blkid_probe_set_magic(pr,
243
5
          offsetof(struct atari_rootsector, part[i]),
244
5
          sizeof(rs->part[i].flags) + sizeof(rs->part[i].id),
245
5
          (unsigned char *) &rs->part[i]))
246
0
        goto err;
247
5
      break;
248
5
    }
249
1.19k
  }
250
251
300
  if (i == 4)
252
295
    goto nothing;
253
254
5
  if (blkid_partitions_need_typeonly(pr))
255
    /* caller does not ask for details about partitions */
256
5
    return BLKID_PROBE_OK;
257
258
0
  ls = blkid_probe_get_partlist(pr);
259
0
  if (!ls)
260
0
    goto nothing;
261
262
0
  tab = blkid_partlist_new_parttable(ls, "atari", 0);
263
0
  if (!tab)
264
0
    goto err;
265
266
0
  for (i = 0; i < ARRAY_SIZE(rs->part); i++) {
267
0
    struct atari_part_def *p = &rs->part[i];
268
269
0
    if (!IS_ACTIVE(*p)) {
270
0
      blkid_partlist_increment_partno(ls);
271
0
      continue;
272
0
    }
273
0
    if (!memcmp(p->id, "XGM", 3)) {
274
0
      has_xgm = 1;
275
0
      rc = parse_extended(pr, ls, tab, p);
276
0
    } else {
277
0
      rc = parse_partition(ls, tab, p, 0);
278
0
    }
279
0
    if (rc < 0)
280
0
      return rc;
281
0
  }
282
283
  /* if there are no XGM partitions, we can try ICD format */
284
  /* if first ICD partition ID is not valid, assume no ICD format */
285
0
  if (!has_xgm && is_id_common(rs->icd_part[0].id)) {
286
0
    for (i = 0; i < ARRAY_SIZE(rs->icd_part); i++) {
287
0
      struct atari_part_def *p = &rs->icd_part[i];
288
289
0
      if (!IS_ACTIVE(*p) || !is_id_common(p->id)) {
290
0
        blkid_partlist_increment_partno(ls);
291
0
        continue;
292
0
      }
293
294
0
      rc = parse_partition(ls, tab, p, 0);
295
0
      if (rc < 0)
296
0
        return rc;
297
0
    }
298
0
  }
299
300
0
  return BLKID_PROBE_OK;
301
302
4.79k
nothing:
303
4.79k
  return BLKID_PROBE_NONE;
304
0
err:
305
  return -ENOMEM;
306
0
}
307
308
const struct blkid_idinfo atari_pt_idinfo =
309
{
310
  .name   = "atari",
311
  .probefunc  = probe_atari_pt,
312
  .magics   = BLKID_NONE_MAGIC
313
};