Coverage Report

Created: 2026-04-28 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/superblocks/udf.c
Line
Count
Source
1
/*
2
 * Copyright (C) 1999 by Andries Brouwer
3
 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4
 * Copyright (C) 2001 by Andreas Dilger
5
 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6
 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
7
 * Copyright (C) 2014-2017 Pali Rohár <pali.rohar@gmail.com>
8
 *
9
 * This file may be redistributed under the terms of the
10
 * GNU Lesser General Public License.
11
 */
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <unistd.h>
15
#include <string.h>
16
#include <errno.h>
17
#include <ctype.h>
18
#include <stdint.h>
19
20
#include "superblocks.h"
21
22
65
#define is_charset_udf(charspec) ((charspec).type == 0 && strncmp((charspec).info, "OSTA Compressed Unicode", sizeof((charspec).info)) == 0)
23
24
0
#define udf_cid_to_enc(cid) ((cid) == 8 ? UL_ENCODE_LATIN1 : (cid) == 16 ? UL_ENCODE_UTF16BE : -1)
25
26
struct charspec {
27
  uint8_t type;
28
  char  info[63];
29
} __attribute__((packed));
30
31
struct dstring128 {
32
  uint8_t cid;
33
  uint8_t c[126];
34
  uint8_t clen;
35
} __attribute__((packed));
36
37
struct dstring32 {
38
  uint8_t cid;
39
  uint8_t c[30];
40
  uint8_t clen;
41
} __attribute__((packed));
42
43
struct dstring36 {
44
  uint8_t cid;
45
  uint8_t c[34];
46
  uint8_t clen;
47
} __attribute__((packed));
48
49
struct volume_descriptor {
50
  struct descriptor_tag {
51
    uint16_t  id;
52
    uint16_t  version;
53
    uint8_t   checksum;
54
    uint8_t   reserved;
55
    uint16_t  serial;
56
    uint16_t  crc;
57
    uint16_t  crc_len;
58
    uint32_t  location;
59
  } __attribute__((packed)) tag;
60
61
  union {
62
    struct anchor_descriptor {
63
      uint32_t  length;
64
      uint32_t  location;
65
    } __attribute__((packed)) anchor;
66
67
    struct primary_descriptor {
68
      uint32_t  seq_num;
69
      uint32_t  desc_num;
70
      struct dstring32 ident;
71
      uint16_t  vds_num;
72
      uint16_t  max_vol_seq;
73
      uint16_t  ichg_lvl;
74
      uint16_t  max_ichg_lvl;
75
      uint32_t  charset_list;
76
      uint32_t  max_charset_list;
77
      struct dstring128 volset_id;
78
      struct charspec desc_charset;
79
      struct charspec exp_charset;
80
      uint32_t  vol_abstract[2];
81
      uint32_t  vol_copyright[2];
82
      uint8_t   app_id_flags;
83
      char    app_id[23];
84
      uint8_t   app_id_reserved[8];
85
      uint8_t   recording_date[12];
86
      uint8_t   imp_id_flags;
87
      char    imp_id[23];
88
      uint8_t   imp_id_os_class;
89
      uint8_t   imp_id_os_id;
90
      uint8_t   imp_id_reserved[6];
91
    } __attribute__((packed)) primary;
92
93
    struct logical_descriptor {
94
      uint32_t  seq_num;
95
      struct charspec desc_charset;
96
      struct dstring128 logvol_id;
97
      uint32_t  logical_blocksize;
98
      uint8_t   domain_id_flags;
99
      char    domain_id[23];
100
      uint16_t  udf_rev;
101
      uint8_t   domain_suffix_flags;
102
      uint8_t   reserved[5];
103
      uint8_t   logical_contents_use[16];
104
      uint32_t  map_table_length;
105
      uint32_t  num_partition_maps;
106
      uint8_t   imp_id[32];
107
      uint8_t   imp_use[128];
108
      uint32_t  lvid_length;
109
      uint32_t  lvid_location;
110
    } __attribute__((packed)) logical;
111
112
    struct logical_vol_integ_descriptor {
113
      uint8_t   recording_date[12];
114
      uint32_t  type;
115
      uint32_t  next_lvid_length;
116
      uint32_t  next_lvid_location;
117
      uint8_t   logical_contents_use[32];
118
      uint32_t  num_partitions;
119
      uint32_t  imp_use_length;
120
    } __attribute__((packed)) logical_vol_integ;
121
122
    struct imp_use_volume_descriptor {
123
      uint32_t  seq_num;
124
      uint8_t   lvi_id_flags;
125
      char    lvi_id[23];
126
      uint16_t  lvi_id_udf_rev;
127
      uint8_t   lvi_id_os_class;
128
      uint8_t   lvi_id_os_id;
129
      uint8_t   lvi_id_reserved[4];
130
      struct charspec lvi_charset;
131
      struct dstring128 logvol_id;
132
      struct dstring36 lvinfo1;
133
      struct dstring36 lvinfo2;
134
      struct dstring36 lvinfo3;
135
    } __attribute__((packed)) imp_use_volume;
136
  } __attribute__((packed)) type;
137
138
} __attribute__((packed));
139
140
46
#define TAG_ID_PVD  1
141
139
#define TAG_ID_AVDP 2
142
15
#define TAG_ID_IUVD 4
143
29
#define TAG_ID_LVD  6
144
49
#define TAG_ID_TD   8
145
0
#define TAG_ID_LVID 9
146
147
struct volume_structure_descriptor {
148
  uint8_t   type;
149
  uint8_t   id[5];
150
  uint8_t   version;
151
} __attribute__((packed));
152
153
1.94k
#define UDF_VSD_OFFSET      0x8000LL
154
155
struct logical_vol_integ_descriptor_imp_use
156
{
157
  uint8_t   imp_id[32];
158
  uint32_t  num_files;
159
  uint32_t  num_dirs;
160
  uint16_t  min_udf_read_rev;
161
  uint16_t  min_udf_write_rev;
162
  uint16_t  max_udf_write_rev;
163
} __attribute__ ((packed));
164
165
0
#define UDF_LVIDIU_OFFSET(vd) (sizeof((vd).tag) + sizeof((vd).type.logical_vol_integ) + (uint64_t) 8 * le32_to_cpu((vd).type.logical_vol_integ.num_partitions))
166
0
#define UDF_LVIDIU_LENGTH(vd) (le32_to_cpu((vd).type.logical_vol_integ.imp_use_length))
167
168
static inline int gen_uuid_from_volset_id(unsigned char uuid[17], struct dstring128 *volset_id)
169
0
{
170
0
  int enc;
171
0
  size_t i;
172
0
  size_t len;
173
0
  size_t clen;
174
0
  size_t nonhexpos;
175
0
  unsigned char buf[17];
176
177
0
  memset(buf, 0, sizeof(buf));
178
179
0
  clen = volset_id->clen;
180
0
  if (clen > 0)
181
0
    --clen;
182
0
  if (clen > sizeof(volset_id->c))
183
0
    clen = sizeof(volset_id->c);
184
185
0
  enc = udf_cid_to_enc(volset_id->cid);
186
0
  if (enc == -1)
187
0
    return -1;
188
189
0
  len = ul_encode_to_utf8(enc, buf, sizeof(buf), volset_id->c, clen);
190
0
  if (len < 8)
191
0
    return -1;
192
193
0
  nonhexpos = 16;
194
0
  for (i = 0; i < 16; ++i) {
195
0
    if (!isxdigit(buf[i])) {
196
0
      nonhexpos = i;
197
0
      break;
198
0
    }
199
0
  }
200
201
0
  if (nonhexpos < 8) {
202
0
    snprintf((char *) uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
203
0
      buf[0], buf[1], buf[2], buf[3],
204
0
      buf[4], buf[5], buf[6], buf[7]);
205
0
  } else if (nonhexpos < 16) {
206
0
    for (i = 0; i < 8; ++i)
207
0
      uuid[i] = tolower(buf[i]);
208
0
    snprintf((char *) uuid + 8, 9, "%02x%02x%02x%02x",
209
0
      buf[8], buf[9], buf[10], buf[11]);
210
0
  } else {
211
0
    for (i = 0; i < 16; ++i)
212
0
      uuid[i] = tolower(buf[i]);
213
0
    uuid[16] = 0;
214
0
  }
215
216
0
  return 0;
217
0
}
218
219
static int probe_udf(blkid_probe pr,
220
    const struct blkid_idmag *mag __attribute__((__unused__)))
221
601
{
222
601
  struct volume_descriptor *vd;
223
601
  struct volume_structure_descriptor *vsd;
224
601
  struct logical_vol_integ_descriptor_imp_use *lvidiu;
225
601
  uint32_t lvid_len = 0;
226
601
  uint32_t lvid_loc = 0;
227
601
  uint64_t s_off;
228
601
  uint32_t bs;
229
601
  uint32_t b;
230
601
  uint16_t type;
231
601
  uint32_t count;
232
601
  uint32_t loc;
233
601
  size_t i;
234
601
  uint32_t vsd_len;
235
601
  uint16_t udf_rev = 0;
236
601
  int is_udf = 0;
237
601
  int vsd_2048_valid = -1;
238
601
  int have_label = 0;
239
601
  int have_uuid = 0;
240
601
  int have_logvolid = 0;
241
601
  int have_volid = 0;
242
601
  int have_volsetid = 0;
243
601
  int have_applicationid = 0;
244
601
  int have_publisherid = 0;
245
246
  /* Session offset */
247
601
  if (blkid_probe_get_hint(pr, "session_offset", &s_off) < 0)
248
601
    s_off = 0;
249
250
  /* The block size of a UDF filesystem is that of the underlying
251
   * storage; we check later on for the special case of image files,
252
   * which may have any block size valid for UDF filesystem */
253
601
  uint32_t pbs[] = { 0, 512, 1024, 2048, 4096 };
254
601
  pbs[0] = blkid_probe_get_sectorsize(pr);
255
256
3.23k
  for (i = 0; i < ARRAY_SIZE(pbs); i++) {
257
    /* Do not try with block size same as sector size two times */
258
2.75k
    if (i != 0 && pbs[0] == pbs[i])
259
598
      continue;
260
261
    /* Do not try with block size which is not divisor of session offset */
262
2.15k
    if (s_off % pbs[i])
263
0
      continue;
264
265
    /* ECMA-167 2/8.4, 2/9.1: Each VSD is either 2048 bytes long or
266
     * its size is same as blocksize (for blocksize > 2048 bytes)
267
     * plus padded with zeros */
268
2.15k
    vsd_len = pbs[i] > 2048 ? pbs[i] : 2048;
269
270
    /* Process 2048 bytes long VSD on first session only once
271
     * as its location is same for any blocksize */
272
2.15k
    if (s_off == 0 && vsd_len == 2048) {
273
1.67k
      if (vsd_2048_valid == 0)
274
726
        continue;
275
953
      if (vsd_2048_valid == 1)
276
352
        goto anchor;
277
953
    }
278
279
    /* Check for a Volume Structure Descriptor (VSD) */
280
1.94k
    for (b = 0; b < 64; b++) {
281
1.94k
      vsd = (struct volume_structure_descriptor *)
282
1.94k
        blkid_probe_get_buffer(pr,
283
1.94k
            s_off + UDF_VSD_OFFSET + b * vsd_len,
284
1.94k
            sizeof(*vsd));
285
1.94k
      if (!vsd)
286
0
        return errno ? -errno : 1;
287
1.94k
      if (vsd->id[0] == '\0')
288
220
        break;
289
1.72k
      if (memcmp(vsd->id, "NSR02", 5) == 0 ||
290
1.64k
          memcmp(vsd->id, "NSR03", 5) == 0)
291
358
        goto anchor;
292
1.36k
      else if (memcmp(vsd->id, "BEA01", 5) != 0 &&
293
1.32k
               memcmp(vsd->id, "BOOT2", 5) != 0 &&
294
1.25k
               memcmp(vsd->id, "CD001", 5) != 0 &&
295
585
               memcmp(vsd->id, "CDW02", 5) != 0 &&
296
554
               memcmp(vsd->id, "TEA01", 5) != 0)
297
        /* ECMA-167 2/8.3.1: The volume recognition sequence is
298
         * terminated by the first sector which is not a valid
299
         * descriptor.
300
         * UDF-2.60 2.1.7: UDF 2.00 and lower revisions do not
301
         * have requirement that NSR descriptor is in Extended Area
302
         * (between BEA01 and TEA01) and that there is only one
303
         * Extended Area. So do not stop scanning after TEA01. */
304
503
        break;
305
1.72k
    }
306
307
723
    if (s_off == 0 && vsd_len == 2048)
308
363
      vsd_2048_valid = 0;
309
310
    /* NSR was not found, try with next block size */
311
723
    continue;
312
313
710
anchor:
314
710
    if (s_off == 0 && vsd_len == 2048)
315
590
      vsd_2048_valid = 1;
316
317
    /* Read Anchor Volume Descriptor (AVDP), detect block size */
318
710
    vd = (struct volume_descriptor *)
319
710
      blkid_probe_get_buffer(pr, s_off + 256 * pbs[i], sizeof(*vd));
320
710
    if (!vd)
321
0
      return errno ? -errno : 1;
322
323
    /* Check that we read correct sector and detected correct block size */
324
710
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 256) {
325
129
      type = le16_to_cpu(vd->tag.id);
326
129
      if (type == TAG_ID_AVDP)
327
118
        goto real_blksz;
328
129
    }
329
330
    /* UDF-2.60: 2.2.3: Unclosed sequential Write-Once media may
331
     * have a single AVDP present at either sector 256 or 512. */
332
592
    vd = (struct volume_descriptor *)
333
592
      blkid_probe_get_buffer(pr, s_off + 512 * pbs[i], sizeof(*vd));
334
592
    if (!vd)
335
0
      return errno ? -errno : 1;
336
337
592
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 512) {
338
10
      type = le16_to_cpu(vd->tag.id);
339
10
      if (type == TAG_ID_AVDP)
340
3
        goto real_blksz;
341
10
    }
342
343
592
  }
344
480
  return 1;
345
346
121
real_blksz:
347
  /* At this stage we detected ISO/IEC 13346 or ECMA-167 filesystem recognition sequence, it does not have to be UDF */
348
349
  /* Use the actual block size from here on out */
350
121
  bs = pbs[i];
351
352
  /* get descriptor list address and block count;
353
   * UDF volume descriptor sequence is short (PVD, LVD, USD, IUVD, TD, etc.),
354
   * cap iteration to avoid DoS from crafted anchor length
355
   * (the kernel uses UDF_MAX_TD_NESTING=64 for a similar purpose) */
356
121
  count = le32_to_cpu(vd->type.anchor.length) / bs;
357
121
  if (count > 64)
358
15
    count = 64;
359
121
  loc = le32_to_cpu(vd->type.anchor.location);
360
361
  /* pick the primary descriptor from the list and read UDF identifiers */
362
167
  for (b = 0; b < count; b++) {
363
119
    vd = (struct volume_descriptor *)
364
119
      blkid_probe_get_buffer(pr,
365
119
          ((uint64_t) loc + b) * bs,
366
119
          sizeof(*vd));
367
119
    if (!vd)
368
5
      return errno ? -errno : 1;
369
114
    type = le16_to_cpu(vd->tag.id);
370
114
    if (type == 0)
371
3
      break;
372
111
    if (le32_to_cpu(vd->tag.location) != loc + b)
373
62
      break;
374
49
    if (type == TAG_ID_TD)
375
3
      break;
376
46
    if (type == TAG_ID_PVD) {
377
17
      if (!have_volid && is_charset_udf(vd->type.primary.desc_charset)) {
378
0
        int enc = udf_cid_to_enc(vd->type.primary.ident.cid);
379
0
        uint8_t clen = vd->type.primary.ident.clen;
380
0
        if (clen > 0)
381
0
          --clen;
382
0
        if (clen > sizeof(vd->type.primary.ident.c))
383
0
          clen = sizeof(vd->type.primary.ident.c);
384
0
        if (enc != -1)
385
0
          have_volid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_ID",
386
0
              vd->type.primary.ident.c, clen, enc);
387
0
      }
388
17
      if (!have_uuid && is_charset_udf(vd->type.primary.desc_charset)) {
389
        /* VolumeSetIdentifier in UDF 2.01 specification:
390
         * =================================================================================
391
         * 2.2.2.5 dstring VolumeSetIdentifier
392
         *
393
         * Interpreted as specifying the identifier for the volume set.
394
         *
395
         * The first 16 characters of this field should be set to a unique value. The
396
         * remainder of the field may be set to any allowed value. Specifically, software
397
         * generating volumes conforming to this specification shall not set this field to a
398
         * fixed or trivial value. Duplicate disks which are intended to be identical may
399
         * contain the same value in this field.
400
         *
401
         * NOTE: The intended purpose of this is to guarantee Volume Sets with unique
402
         * identifiers. The first 8 characters of the unique part should come from a CS0
403
         * hexadecimal representation of a 32-bit time value. The remaining 8 characters
404
         * are free for implementation use.
405
         * =================================================================================
406
         *
407
         * Implementation in libblkid:
408
         * The first 16 (Unicode) characters of VolumeSetIdentifier are encoded to UTF-8
409
         * and then first 16 UTF-8 bytes are used to generate UUID. If all 16 bytes are
410
         * hexadecimal digits then their lowercase variants are used as UUID. If one of
411
         * the first 8 bytes (time value) is not hexadecimal digit then first 8 bytes are
412
         * encoded to their hexadecimal representations, resulting in 16 characters and
413
         * set as UUID. If all first 8 bytes (time value) are hexadecimal digits but some
414
         * remaining not then lowercase variant of the first 8 bytes are used as first
415
         * part of UUID and next 4 bytes encoded in hexadecimal representations (resulting
416
         * in 8 characters) are used as second part of UUID string.
417
         */
418
0
        unsigned char uuid[17];
419
0
        if (gen_uuid_from_volset_id(uuid, &vd->type.primary.volset_id) == 0)
420
0
          have_uuid = !blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
421
0
      }
422
17
      if (!have_volsetid && is_charset_udf(vd->type.primary.desc_charset)) {
423
0
        int enc = udf_cid_to_enc(vd->type.primary.volset_id.cid);
424
0
        uint8_t clen = vd->type.primary.volset_id.clen;
425
0
        if (clen > 0)
426
0
          --clen;
427
0
        if (clen > sizeof(vd->type.primary.volset_id.c))
428
0
          clen = sizeof(vd->type.primary.volset_id.c);
429
0
        if (enc != -1)
430
0
          have_volsetid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID",
431
0
              vd->type.primary.volset_id.c, clen, enc);
432
0
      }
433
17
      if (!have_applicationid) {
434
        /* UDF-2.60: 2.2.2.9: This field specifies a valid Entity Identifier identifying the application that last wrote this field */
435
17
        const unsigned char *app_id = (const unsigned char *)vd->type.primary.app_id;
436
17
        size_t app_id_len = strnlen(vd->type.primary.app_id, sizeof(vd->type.primary.app_id));
437
17
        if (app_id_len > 0 && app_id[0] == '*') {
438
3
          app_id++;
439
3
          app_id_len--;
440
3
        }
441
        /* When Application Identifier is not set then use Developer ID from Implementation Identifier */
442
17
        if (app_id_len == 0) {
443
          /* UDF-2.60: 2.1.5.2: "*Developer ID" refers to an Entity Identifier that uniquely identifies the current implementation */
444
6
          app_id = (const unsigned char *)vd->type.primary.imp_id;
445
6
          app_id_len = strnlen(vd->type.primary.imp_id, sizeof(vd->type.primary.imp_id));
446
6
          if (app_id_len > 0 && app_id[0] == '*') {
447
0
            app_id++;
448
0
            app_id_len--;
449
0
          }
450
6
        }
451
17
        if (app_id_len > 0) {
452
          /* UDF-2.60: 2.1.5.2: Values used by UDF for this field are specified in terms of ASCII character strings */
453
14
          have_applicationid = !blkid_probe_set_id_label(pr, "APPLICATION_ID", app_id, app_id_len);
454
14
        }
455
17
      }
456
29
    } else if (type == TAG_ID_LVD) {
457
14
      if (!lvid_len || !lvid_loc) {
458
14
        uint32_t num_partition_maps = le32_to_cpu(vd->type.logical.num_partition_maps);
459
        /* ECMA-167 3/10.6.12: If num_partition_maps is 0, then no LVID is specified */
460
14
        if (num_partition_maps) {
461
10
          lvid_len = le32_to_cpu(vd->type.logical.lvid_length);
462
10
          lvid_loc = le32_to_cpu(vd->type.logical.lvid_location);
463
10
        }
464
14
      }
465
14
      if (!is_udf || !udf_rev) {
466
        /* UDF-2.60: 2.2.4.3: This field shall indicate that the contents of
467
         * this logical volume conforms to the domain defined in this document.
468
         * This distinguish UDF from all other ISO/IEC 13346 and ECMA-167 filesystems. */
469
14
        if (strncmp(vd->type.logical.domain_id, "*OSTA UDF Compliant", sizeof(vd->type.logical.domain_id)) == 0) {
470
0
          is_udf = 1;
471
          /* UDF-2.60: 2.1.5.3: UDF revision field shall indicate revision of UDF document
472
           * We use maximal value from this field and from LVIDIU fields for ID_FS_VERSION */
473
0
          if (!udf_rev)
474
0
            udf_rev = le16_to_cpu(vd->type.logical.udf_rev);
475
0
        }
476
14
      }
477
14
      if ((!have_logvolid || !have_label) && is_charset_udf(vd->type.logical.desc_charset)) {
478
        /* LogicalVolumeIdentifier in UDF 2.01 specification:
479
         * ===============================================================
480
         * 2. Basic Restrictions & Requirements
481
         *
482
         * Logical Volume Descriptor
483
         *
484
         * There shall be exactly one prevailing Logical Volume
485
         * Descriptor recorded per Volume Set.
486
         *
487
         * The LogicalVolumeIdentifier field shall not be null and
488
         * should contain an identifier that aids in the identification of
489
         * the logical volume. Specifically, software generating
490
         * volumes conforming to this specification shall not set this
491
         * field to a fixed or trivial value. Duplicate disks, which are
492
         * intended to be identical, may contain the same value in this
493
         * field. This field is extremely important in logical volume
494
         * identification when multiple media are present within a
495
         * jukebox. This name is typically what is displayed to the user.
496
         * ===============================================================
497
         *
498
         * Implementation in libblkid:
499
         * The LogicalVolumeIdentifier field is used for LABEL. MS Windows
500
         * read Volume Label also from LogicalVolumeIdentifier. Grub2 read
501
         * LABEL also from this field. Program newfs_udf (from UDFclient)
502
         * when formatting disk set this field from user option Disc Name.
503
         */
504
0
        int enc = udf_cid_to_enc(vd->type.logical.logvol_id.cid);
505
0
        uint8_t clen = vd->type.logical.logvol_id.clen;
506
0
        if (clen > 0)
507
0
          --clen;
508
0
        if (clen > sizeof(vd->type.logical.logvol_id.c))
509
0
          clen = sizeof(vd->type.logical.logvol_id.c);
510
0
        if (enc != -1) {
511
0
          if (!have_label)
512
0
            have_label = !blkid_probe_set_utf8label(pr,
513
0
                vd->type.logical.logvol_id.c, clen, enc);
514
0
          if (!have_logvolid)
515
0
            have_logvolid = !blkid_probe_set_utf8_id_label(pr, "LOGICAL_VOLUME_ID",
516
0
                vd->type.logical.logvol_id.c, clen, enc);
517
0
        }
518
0
      }
519
15
    } else if (type == TAG_ID_IUVD) {
520
3
      if (!have_publisherid && strncmp(vd->type.imp_use_volume.lvi_id, "*UDF LV Info", sizeof(vd->type.imp_use_volume.lvi_id)) == 0 && is_charset_udf(vd->type.imp_use_volume.lvi_charset)) {
521
        /* UDF-2.60: 2.2.7.2.3: Field LVInfo1 could contain information such as Owner Name
522
         * More UDF generating tools set this field to person who creating the filesystem
523
         * therefore its meaning is similar to ISO9660 Publisher Identifier. So for
524
         * compatibility with iso9660 superblock code export this field via PUBLISHER_ID.
525
         */
526
0
        int enc = udf_cid_to_enc(vd->type.imp_use_volume.lvinfo1.cid);
527
0
        uint8_t clen = vd->type.imp_use_volume.lvinfo1.clen;
528
0
        if (clen > 0)
529
0
          --clen;
530
0
        if (clen > sizeof(vd->type.imp_use_volume.lvinfo1.c))
531
0
          clen = sizeof(vd->type.imp_use_volume.lvinfo1.c);
532
0
        if (enc != -1)
533
0
          have_publisherid = !blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID",
534
0
                vd->type.imp_use_volume.lvinfo1.c, clen, enc);
535
0
      }
536
3
    }
537
46
    if (is_udf && have_volid && have_uuid && have_volsetid && have_logvolid && have_label && lvid_len && lvid_loc && have_applicationid && have_publisherid)
538
0
      break;
539
46
  }
540
541
116
  if (!is_udf) {
542
    /* We detected some other ISO/IEC 13346 or ECMA-167 filesystem, not UDF */
543
116
    return 1;
544
116
  }
545
546
  /* Pick the first logical volume integrity descriptor and read UDF revision */
547
0
  if (lvid_loc && lvid_len >= sizeof(*vd)) {
548
0
    vd = (struct volume_descriptor *)
549
0
      blkid_probe_get_buffer(pr,
550
0
          (uint64_t) lvid_loc * bs,
551
0
          sizeof(*vd));
552
0
    if (!vd)
553
0
      return errno ? -errno : 1;
554
0
    type = le16_to_cpu(vd->tag.id);
555
0
    if (type == TAG_ID_LVID &&
556
0
        le32_to_cpu(vd->tag.location) == lvid_loc &&
557
0
        UDF_LVIDIU_LENGTH(*vd) >= sizeof(*lvidiu)) {
558
      /* ECMA-167 3/8.8.2: There is stored sequence of LVIDs and valid is just last
559
       * one. So correctly we should jump to next_lvid_location and read next LVID
560
       * until we find last one. This could be time consuming process and could
561
       * lead to scanning lot of disk blocks. Because we use LVID only for UDF
562
       * version, in the worst case we would report only wrong ID_FS_VERSION. */
563
0
      uint16_t lvidiu_udf_rev;
564
0
      lvidiu = (struct logical_vol_integ_descriptor_imp_use *)
565
0
        blkid_probe_get_buffer(pr,
566
0
            (uint64_t) lvid_loc * bs + UDF_LVIDIU_OFFSET(*vd),
567
0
            sizeof(*lvidiu));
568
0
      if (!lvidiu)
569
0
        return errno ? -errno : 1;
570
      /* UDF-2.60: 2. Basic Restrictions & Requirements:
571
       * The Minimum UDF Read Revision value shall be at most #0250
572
       * for all media with a UDF 2.60 file system.
573
       * Because some 2.60 implementations put 2.50 into both LVIDIU
574
       * fields and 2.60 into LVD, use maximal value from LVD,
575
       * Minimum UDF Read Revision and Minimum UDF Write Revision for
576
       * ID_FS_VERSION to distinguish between UDF 2.50 and UDF 2.60 discs. */
577
0
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_read_rev);
578
0
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
579
0
        udf_rev = lvidiu_udf_rev;
580
0
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_write_rev);
581
0
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
582
0
        udf_rev = lvidiu_udf_rev;
583
0
    }
584
0
  }
585
586
0
  if (udf_rev)
587
    /* UDF revision is stored as decimal number in hexadecimal format.
588
     * E.g. number 0x0150 is revision 1.50, number 0x0201 is revision 2.01. */
589
0
    blkid_probe_sprintf_version(pr, "%x.%02x", (unsigned int)(udf_rev >> 8), (unsigned int)(udf_rev & 0xFF));
590
591
0
  blkid_probe_set_fsblocksize(pr, bs);
592
0
  blkid_probe_set_block_size(pr, bs);
593
594
0
  return 0;
595
0
}
596
597
598
const struct blkid_idinfo udf_idinfo =
599
{
600
  .name   = "udf",
601
  .usage    = BLKID_USAGE_FILESYSTEM,
602
  .probefunc  = probe_udf,
603
  .flags    = BLKID_IDINFO_TOLERANT,
604
  .magics   =
605
  {
606
    /* These magics are generic to all ISO/IEC 13346 and ECMA-167 filesystems, not just UDF */
607
    { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
608
    { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
609
    { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
610
    { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
611
    { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
612
    { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
613
    { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
614
    { NULL }
615
  }
616
};