Coverage Report

Created: 2025-10-12 06:56

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
837
static int linux_isalnum(unsigned char c) {
70
837
  return _linux_isalnum[c];
71
837
}
72
73
837
#define isalnum linux_isalnum
74
75
0
#define IS_ACTIVE(partdef) ((partdef).flags & 1)
76
77
static int is_valid_dimension(uint32_t start, uint32_t size, uint32_t maxoff)
78
691
{
79
691
  uint64_t end = start + size;
80
81
691
  return  end >= start
82
524
    && 0 < start && start <= maxoff
83
212
    && 0 < size && size <= maxoff
84
68
    && 0 < end && end <= maxoff;
85
691
}
86
87
static int is_valid_partition(struct atari_part_def *part, uint32_t maxoff)
88
764
{
89
764
  uint32_t start = be32_to_cpu(part->start),
90
764
     size = be32_to_cpu(part->size);
91
92
764
  return (part->flags & 1)
93
335
    && isalnum(part->id[0])
94
274
    && isalnum(part->id[1])
95
228
    && isalnum(part->id[2])
96
199
    && is_valid_dimension(start, size, maxoff);
97
764
}
98
99
static int is_id_common(char *id)
100
0
{
101
0
  const char *ids[] = {"GEM", "BGM", "LNX", "SWP", "RAW", };
102
0
  unsigned i;
103
104
0
  for (i = 0; i < ARRAY_SIZE(ids); i++) {
105
0
    if (!memcmp(ids[i], id, 3))
106
0
      return 1;
107
0
  }
108
0
  return 0;
109
0
}
110
111
static int parse_partition(blkid_partlist ls, blkid_parttable tab,
112
  struct atari_part_def *part, uint32_t offset)
113
0
{
114
0
  blkid_partition par;
115
0
  uint32_t start;
116
0
  uint32_t size;
117
118
0
  start = be32_to_cpu(part->start) + offset;
119
0
  size = be32_to_cpu(part->size);
120
121
0
  if (blkid_partlist_get_partition_by_start(ls, start)) {
122
    /* Don't increment partno for extended parts */
123
0
    if (!offset)
124
0
      blkid_partlist_increment_partno(ls);
125
0
    return 0;
126
0
  }
127
128
0
  par = blkid_partlist_add_partition(ls, tab, start, size);
129
0
  if (!par)
130
0
    return -ENOMEM;
131
132
0
  blkid_partition_set_type_string(par, (unsigned char *) part->id,
133
0
          sizeof(part->id));
134
0
  return 1;
135
0
}
136
137
/*
138
 * \return 1: OK, 0: bad format or -errno
139
 */
140
static int parse_extended(blkid_probe pr, blkid_partlist ls,
141
  blkid_parttable tab, struct atari_part_def *part)
142
0
{
143
0
  uint32_t x0start, xstart;
144
0
  unsigned ct = 0, i = 0;
145
0
  int rc;
146
147
0
  x0start = xstart = be32_to_cpu(part->start);
148
0
  while (1) {
149
0
    struct atari_rootsector *xrs;
150
151
0
    if (++ct > 100)
152
0
      break;
153
154
0
    xrs = (struct atari_rootsector *) blkid_probe_get_sector(pr, xstart);
155
0
    if (!xrs) {
156
0
      if (errno)
157
0
        return -errno;
158
0
      return 0;
159
0
    }
160
161
    /*
162
     * There must be data partition followed by reference to next
163
     * XGM or inactive entry.
164
     */
165
0
    for (i=0; ; i++) {
166
0
      if (i >= ARRAY_SIZE(xrs->part) - 1)
167
0
        return 0;
168
0
      if (IS_ACTIVE(xrs->part[i]))
169
0
        break;
170
0
    }
171
172
0
    if (!memcmp(xrs->part[i].id, "XGM", 3))
173
0
      return 0;
174
175
0
    rc = parse_partition(ls, tab, &xrs->part[i], xstart);
176
0
    if (rc <= 0)
177
0
      return rc;
178
179
0
    if (!IS_ACTIVE(xrs->part[i+1]))
180
0
      break;
181
182
0
    if (memcmp(xrs->part[i+1].id, "XGM", 3) != 0)
183
0
      return 0;
184
185
0
    xstart = x0start + be32_to_cpu(xrs->part[i+1].start);
186
0
  }
187
188
0
  return 1;
189
0
}
190
191
static int probe_atari_pt(blkid_probe pr,
192
    const struct blkid_idmag *mag __attribute__((__unused__)))
193
3.51k
{
194
3.51k
  struct atari_rootsector *rs;
195
196
3.51k
  blkid_parttable tab = NULL;
197
3.51k
  blkid_partlist ls;
198
199
3.51k
  unsigned i;
200
3.51k
  int has_xgm = 0;
201
3.51k
  int rc = 0;
202
3.51k
  uint32_t rssize;  /* size in sectors from root sector */
203
3.51k
  uint64_t size;    /* size in sectors from system */
204
205
  /* Atari partition is not defined for other sector sizes */
206
3.51k
  if (blkid_probe_get_sectorsize(pr) != 512)
207
0
    goto nothing;
208
209
3.51k
  size = blkid_probe_get_size(pr) / 512;
210
211
  /* Atari is not well defined to support large disks */
212
3.51k
  if (size > INT32_MAX)
213
0
    goto nothing;
214
215
  /* read root sector */
216
3.51k
  rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0);
217
3.51k
  if (!rs) {
218
0
    if (errno)
219
0
      return -errno;
220
0
    goto nothing;
221
0
  }
222
223
3.51k
  rssize = be32_to_cpu(rs->hd_size);
224
225
  /* check number of sectors stored in the root sector */
226
3.51k
  if (rssize < 2 || rssize > size)
227
2.87k
    goto nothing;
228
229
  /* check list of bad blocks */
230
643
  if ((rs->bsl_start || rs->bsl_len)
231
492
      && !is_valid_dimension(be32_to_cpu(rs->bsl_start),
232
492
           be32_to_cpu(rs->bsl_len),
233
492
           rssize))
234
452
    goto nothing;
235
236
  /*
237
   * At least one valid partition required
238
   */
239
951
  for (i = 0; i < 4; i++) {
240
764
    if (is_valid_partition(&rs->part[i], rssize)) {
241
4
      if (blkid_probe_set_magic(pr,
242
4
          offsetof(struct atari_rootsector, part[i]),
243
4
          sizeof(rs->part[i].flags) + sizeof(rs->part[i].id),
244
4
          (unsigned char *) &rs->part[i]))
245
0
        goto err;
246
4
      break;
247
4
    }
248
764
  }
249
250
191
  if (i == 4)
251
187
    goto nothing;
252
253
4
  if (blkid_partitions_need_typeonly(pr))
254
    /* caller does not ask for details about partitions */
255
4
    return BLKID_PROBE_OK;
256
257
0
  ls = blkid_probe_get_partlist(pr);
258
0
  if (!ls)
259
0
    goto nothing;
260
261
0
  tab = blkid_partlist_new_parttable(ls, "atari", 0);
262
0
  if (!tab)
263
0
    goto err;
264
265
0
  for (i = 0; i < ARRAY_SIZE(rs->part); i++) {
266
0
    struct atari_part_def *p = &rs->part[i];
267
268
0
    if (!IS_ACTIVE(*p)) {
269
0
      blkid_partlist_increment_partno(ls);
270
0
      continue;
271
0
    }
272
0
    if (!memcmp(p->id, "XGM", 3)) {
273
0
      has_xgm = 1;
274
0
      rc = parse_extended(pr, ls, tab, p);
275
0
    } else {
276
0
      rc = parse_partition(ls, tab, p, 0);
277
0
    }
278
0
    if (rc < 0)
279
0
      return rc;
280
0
  }
281
282
  /* if there are no XGM partitions, we can try ICD format */
283
  /* if first ICD partition ID is not valid, assume no ICD format */
284
0
  if (!has_xgm && is_id_common(rs->icd_part[0].id)) {
285
0
    for (i = 0; i < ARRAY_SIZE(rs->icd_part); i++) {
286
0
      struct atari_part_def *p = &rs->icd_part[i];
287
288
0
      if (!IS_ACTIVE(*p) || !is_id_common(p->id)) {
289
0
        blkid_partlist_increment_partno(ls);
290
0
        continue;
291
0
      }
292
293
0
      rc = parse_partition(ls, tab, p, 0);
294
0
      if (rc < 0)
295
0
        return rc;
296
0
    }
297
0
  }
298
299
0
  return BLKID_PROBE_OK;
300
301
3.51k
nothing:
302
3.51k
  return BLKID_PROBE_NONE;
303
0
err:
304
  return -ENOMEM;
305
0
}
306
307
const struct blkid_idinfo atari_pt_idinfo =
308
{
309
  .name   = "atari",
310
  .probefunc  = probe_atari_pt,
311
  .magics   = BLKID_NONE_MAGIC
312
};