Coverage Report

Created: 2025-11-16 06:06

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
2.01k
#define is_charset_udf(charspec) ((charspec).type == 0 && strncmp((charspec).info, "OSTA Compressed Unicode", sizeof((charspec).info)) == 0)
23
24
929
#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
1.71k
#define TAG_ID_PVD  1
141
528
#define TAG_ID_AVDP 2
142
697
#define TAG_ID_IUVD 4
143
1.22k
#define TAG_ID_LVD  6
144
1.75k
#define TAG_ID_TD   8
145
182
#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
2.03k
#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
48
#define UDF_LVIDIU_OFFSET(vd) (sizeof((vd).tag) + sizeof((vd).type.logical_vol_integ) + 2 * 4 * le32_to_cpu((vd).type.logical_vol_integ.num_partitions))
166
51
#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
234
{
170
234
  int enc;
171
234
  size_t i;
172
234
  size_t len;
173
234
  size_t clen;
174
234
  size_t nonhexpos;
175
234
  unsigned char buf[17];
176
177
234
  memset(buf, 0, sizeof(buf));
178
179
234
  clen = volset_id->clen;
180
234
  if (clen > 0)
181
224
    --clen;
182
234
  if (clen > sizeof(volset_id->c))
183
20
    clen = sizeof(volset_id->c);
184
185
234
  enc = udf_cid_to_enc(volset_id->cid);
186
234
  if (enc == -1)
187
23
    return -1;
188
189
211
  len = ul_encode_to_utf8(enc, buf, sizeof(buf), volset_id->c, clen);
190
211
  if (len < 8)
191
8
    return -1;
192
193
203
  nonhexpos = 16;
194
2.22k
  for (i = 0; i < 16; ++i) {
195
2.12k
    if (!isxdigit(buf[i])) {
196
106
      nonhexpos = i;
197
106
      break;
198
106
    }
199
2.12k
  }
200
201
203
  if (nonhexpos < 8) {
202
63
    snprintf((char *) uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
203
63
      buf[0], buf[1], buf[2], buf[3],
204
63
      buf[4], buf[5], buf[6], buf[7]);
205
140
  } else if (nonhexpos < 16) {
206
387
    for (i = 0; i < 8; ++i)
207
344
      uuid[i] = tolower(buf[i]);
208
43
    snprintf((char *) uuid + 8, 9, "%02x%02x%02x%02x",
209
43
      buf[8], buf[9], buf[10], buf[11]);
210
97
  } else {
211
1.64k
    for (i = 0; i < 16; ++i)
212
1.55k
      uuid[i] = tolower(buf[i]);
213
97
    uuid[16] = 0;
214
97
  }
215
216
203
  return 0;
217
211
}
218
219
static int probe_udf(blkid_probe pr,
220
    const struct blkid_idmag *mag __attribute__((__unused__)))
221
784
{
222
784
  struct volume_descriptor *vd;
223
784
  struct volume_structure_descriptor *vsd;
224
784
  struct logical_vol_integ_descriptor_imp_use *lvidiu;
225
784
  uint32_t lvid_len = 0;
226
784
  uint32_t lvid_loc = 0;
227
784
  uint64_t s_off;
228
784
  uint32_t bs;
229
784
  uint32_t b;
230
784
  uint16_t type;
231
784
  uint32_t count;
232
784
  uint32_t loc;
233
784
  size_t i;
234
784
  uint32_t vsd_len;
235
784
  uint16_t udf_rev = 0;
236
784
  int is_udf = 0;
237
784
  int vsd_2048_valid = -1;
238
784
  int have_label = 0;
239
784
  int have_uuid = 0;
240
784
  int have_logvolid = 0;
241
784
  int have_volid = 0;
242
784
  int have_volsetid = 0;
243
784
  int have_applicationid = 0;
244
784
  int have_publisherid = 0;
245
246
  /* Session offset */
247
784
  if (blkid_probe_get_hint(pr, "session_offset", &s_off) < 0)
248
784
    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
784
  uint32_t pbs[] = { 0, 512, 1024, 2048, 4096 };
254
784
  pbs[0] = blkid_probe_get_sectorsize(pr);
255
256
1.42k
  for (i = 0; i < ARRAY_SIZE(pbs); i++) {
257
    /* Do not try with block size same as sector size two times */
258
1.38k
    if (i != 0 && pbs[0] == pbs[i])
259
167
      continue;
260
261
    /* Do not try with block size which is not divisor of session offset */
262
1.21k
    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
1.21k
    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
1.21k
    if (s_off == 0 && vsd_len == 2048) {
273
1.09k
      if (vsd_2048_valid == 0)
274
238
        continue;
275
861
      if (vsd_2048_valid == 1)
276
77
        goto anchor;
277
861
    }
278
279
    /* Check for a Volume Structure Descriptor (VSD) */
280
2.03k
    for (b = 0; b < 64; b++) {
281
2.03k
      vsd = (struct volume_structure_descriptor *)
282
2.03k
        blkid_probe_get_buffer(pr,
283
2.03k
            s_off + UDF_VSD_OFFSET + b * vsd_len,
284
2.03k
            sizeof(*vsd));
285
2.03k
      if (!vsd)
286
175
        return errno ? -errno : 1;
287
1.85k
      if (vsd->id[0] == '\0')
288
51
        break;
289
1.80k
      if (memcmp(vsd->id, "NSR02", 5) == 0 ||
290
1.67k
          memcmp(vsd->id, "NSR03", 5) == 0)
291
569
        goto anchor;
292
1.23k
      else if (memcmp(vsd->id, "BEA01", 5) != 0 &&
293
694
               memcmp(vsd->id, "BOOT2", 5) != 0 &&
294
602
               memcmp(vsd->id, "CD001", 5) != 0 &&
295
201
               memcmp(vsd->id, "CDW02", 5) != 0 &&
296
179
               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
108
        break;
305
1.80k
    }
306
307
159
    if (s_off == 0 && vsd_len == 2048)
308
119
      vsd_2048_valid = 0;
309
310
    /* NSR was not found, try with next block size */
311
159
    continue;
312
313
646
anchor:
314
646
    if (s_off == 0 && vsd_len == 2048)
315
645
      vsd_2048_valid = 1;
316
317
    /* Read Anchor Volume Descriptor (AVDP), detect block size */
318
646
    vd = (struct volume_descriptor *)
319
646
      blkid_probe_get_buffer(pr, s_off + 256 * pbs[i], sizeof(*vd));
320
646
    if (!vd)
321
7
      return errno ? -errno : 1;
322
323
    /* Check that we read correct sector and detected correct block size */
324
639
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 256) {
325
524
      type = le16_to_cpu(vd->tag.id);
326
524
      if (type == TAG_ID_AVDP)
327
518
        goto real_blksz;
328
524
    }
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
121
    vd = (struct volume_descriptor *)
333
121
      blkid_probe_get_buffer(pr, s_off + 512 * pbs[i], sizeof(*vd));
334
121
    if (!vd)
335
43
      return errno ? -errno : 1;
336
337
78
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 512) {
338
4
      type = le16_to_cpu(vd->tag.id);
339
4
      if (type == TAG_ID_AVDP)
340
1
        goto real_blksz;
341
4
    }
342
343
78
  }
344
40
  return 1;
345
346
519
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
519
  bs = pbs[i];
351
352
  /* get descriptor list address and block count */
353
519
  count = le32_to_cpu(vd->type.anchor.length) / bs;
354
519
  loc = le32_to_cpu(vd->type.anchor.location);
355
356
  /* pick the primary descriptor from the list and read UDF identifiers */
357
2.22k
  for (b = 0; b < count; b++) {
358
2.21k
    vd = (struct volume_descriptor *)
359
2.21k
      blkid_probe_get_buffer(pr,
360
2.21k
          (uint64_t) (loc + b) * bs,
361
2.21k
          sizeof(*vd));
362
2.21k
    if (!vd)
363
53
      return errno ? -errno : 1;
364
2.16k
    type = le16_to_cpu(vd->tag.id);
365
2.16k
    if (type == 0)
366
186
      break;
367
1.97k
    if (le32_to_cpu(vd->tag.location) != loc + b)
368
223
      break;
369
1.75k
    if (type == TAG_ID_TD)
370
46
      break;
371
1.71k
    if (type == TAG_ID_PVD) {
372
486
      if (!have_volid && is_charset_udf(vd->type.primary.desc_charset)) {
373
234
        int enc = udf_cid_to_enc(vd->type.primary.ident.cid);
374
234
        uint8_t clen = vd->type.primary.ident.clen;
375
234
        if (clen > 0)
376
184
          --clen;
377
234
        if (clen > sizeof(vd->type.primary.ident.c))
378
19
          clen = sizeof(vd->type.primary.ident.c);
379
234
        if (enc != -1)
380
218
          have_volid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_ID",
381
218
              vd->type.primary.ident.c, clen, enc);
382
234
      }
383
486
      if (!have_uuid && is_charset_udf(vd->type.primary.desc_charset)) {
384
        /* VolumeSetIdentifier in UDF 2.01 specification:
385
         * =================================================================================
386
         * 2.2.2.5 dstring VolumeSetIdentifier
387
         *
388
         * Interpreted as specifying the identifier for the volume set.
389
         *
390
         * The first 16 characters of this field should be set to a unique value. The
391
         * remainder of the field may be set to any allowed value. Specifically, software
392
         * generating volumes conforming to this specification shall not set this field to a
393
         * fixed or trivial value. Duplicate disks which are intended to be identical may
394
         * contain the same value in this field.
395
         *
396
         * NOTE: The intended purpose of this is to guarantee Volume Sets with unique
397
         * identifiers. The first 8 characters of the unique part should come from a CS0
398
         * hexadecimal representation of a 32-bit time value. The remaining 8 characters
399
         * are free for implementation use.
400
         * =================================================================================
401
         *
402
         * Implementation in libblkid:
403
         * The first 16 (Unicode) characters of VolumeSetIdentifier are encoded to UTF-8
404
         * and then first 16 UTF-8 bytes are used to generate UUID. If all 16 bytes are
405
         * hexadecimal digits then their lowercase variants are used as UUID. If one of
406
         * the first 8 bytes (time value) is not hexadecimal digit then first 8 bytes are
407
         * encoded to their hexadecimal representations, resulting in 16 characters and
408
         * set as UUID. If all first 8 bytes (time value) are hexadecimal digits but some
409
         * remaining not then lowercase variant of the first 8 bytes are used as first
410
         * part of UUID and next 4 bytes encoded in hexadecimal representations (resulting
411
         * in 8 characters) are used as second part of UUID string.
412
         */
413
234
        unsigned char uuid[17];
414
234
        if (gen_uuid_from_volset_id(uuid, &vd->type.primary.volset_id) == 0)
415
203
          have_uuid = !blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
416
234
      }
417
486
      if (!have_volsetid && is_charset_udf(vd->type.primary.desc_charset)) {
418
234
        int enc = udf_cid_to_enc(vd->type.primary.volset_id.cid);
419
234
        uint8_t clen = vd->type.primary.volset_id.clen;
420
234
        if (clen > 0)
421
224
          --clen;
422
234
        if (clen > sizeof(vd->type.primary.volset_id.c))
423
20
          clen = sizeof(vd->type.primary.volset_id.c);
424
234
        if (enc != -1)
425
211
          have_volsetid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID",
426
211
              vd->type.primary.volset_id.c, clen, enc);
427
234
      }
428
486
      if (!have_applicationid) {
429
        /* UDF-2.60: 2.2.2.9: This field specifies a valid Entity Identifier identifying the application that last wrote this field */
430
471
        const unsigned char *app_id = (const unsigned char *)vd->type.primary.app_id;
431
471
        size_t app_id_len = strnlen(vd->type.primary.app_id, sizeof(vd->type.primary.app_id));
432
471
        if (app_id_len > 0 && app_id[0] == '*') {
433
229
          app_id++;
434
229
          app_id_len--;
435
229
        }
436
        /* When Application Identifier is not set then use Developer ID from Implementation Identifier */
437
471
        if (app_id_len == 0) {
438
          /* UDF-2.60: 2.1.5.2: "*Developer ID" refers to an Entity Identifier that uniquely identifies the current implementation */
439
189
          app_id = (const unsigned char *)vd->type.primary.imp_id;
440
189
          app_id_len = strnlen(vd->type.primary.imp_id, sizeof(vd->type.primary.imp_id));
441
189
          if (app_id_len > 0 && app_id[0] == '*') {
442
42
            app_id++;
443
42
            app_id_len--;
444
42
          }
445
189
        }
446
471
        if (app_id_len > 0) {
447
          /* UDF-2.60: 2.1.5.2: Values used by UDF for this field are specified in terms of ASCII character strings */
448
385
          have_applicationid = !blkid_probe_set_id_label(pr, "APPLICATION_ID", app_id, app_id_len);
449
385
        }
450
471
      }
451
1.22k
    } else if (type == TAG_ID_LVD) {
452
527
      if (!lvid_len || !lvid_loc) {
453
455
        uint32_t num_partition_maps = le32_to_cpu(vd->type.logical.num_partition_maps);
454
        /* ECMA-167 3/10.6.12: If num_partition_maps is 0, then no LVID is specified */
455
455
        if (num_partition_maps) {
456
393
          lvid_len = le32_to_cpu(vd->type.logical.lvid_length);
457
393
          lvid_loc = le32_to_cpu(vd->type.logical.lvid_location);
458
393
        }
459
455
      }
460
527
      if (!is_udf || !udf_rev) {
461
        /* UDF-2.60: 2.2.4.3: This field shall indicate that the contents of
462
         * this logical volume conforms to the domain defined in this document.
463
         * This distinguish UDF from all other ISO/IEC 13346 and ECMA-167 filesystems. */
464
476
        if (strncmp(vd->type.logical.domain_id, "*OSTA UDF Compliant", sizeof(vd->type.logical.domain_id)) == 0) {
465
261
          is_udf = 1;
466
          /* UDF-2.60: 2.1.5.3: UDF revision field shall indicate revision of UDF document
467
           * We use maximal value from this field and from LVIDIU fields for ID_FS_VERSION */
468
261
          if (!udf_rev)
469
261
            udf_rev = le16_to_cpu(vd->type.logical.udf_rev);
470
261
        }
471
476
      }
472
527
      if ((!have_logvolid || !have_label) && is_charset_udf(vd->type.logical.desc_charset)) {
473
        /* LogicalVolumeIdentifier in UDF 2.01 specification:
474
         * ===============================================================
475
         * 2. Basic Restrictions & Requirements
476
         *
477
         * Logical Volume Descriptor
478
         *
479
         * There shall be exactly one prevailing Logical Volume
480
         * Descriptor recorded per Volume Set.
481
         *
482
         * The LogicalVolumeIdentifier field shall not be null and
483
         * should contain an identifier that aids in the identification of
484
         * the logical volume. Specifically, software generating
485
         * volumes conforming to this specification shall not set this
486
         * field to a fixed or trivial value. Duplicate disks, which are
487
         * intended to be identical, may contain the same value in this
488
         * field. This field is extremely important in logical volume
489
         * identification when multiple media are present within a
490
         * jukebox. This name is typically what is displayed to the user.
491
         * ===============================================================
492
         *
493
         * Implementation in libblkid:
494
         * The LogicalVolumeIdentifier field is used for LABEL. MS Windows
495
         * read Volume Label also from LogicalVolumeIdentifier. Grub2 read
496
         * LABEL also from this field. Program newfs_udf (from UDFclient)
497
         * when formatting disk set this field from user option Disc Name.
498
         */
499
194
        int enc = udf_cid_to_enc(vd->type.logical.logvol_id.cid);
500
194
        uint8_t clen = vd->type.logical.logvol_id.clen;
501
194
        if (clen > 0)
502
149
          --clen;
503
194
        if (clen > sizeof(vd->type.logical.logvol_id.c))
504
9
          clen = sizeof(vd->type.logical.logvol_id.c);
505
194
        if (enc != -1) {
506
170
          if (!have_label)
507
170
            have_label = !blkid_probe_set_utf8label(pr,
508
170
                vd->type.logical.logvol_id.c, clen, enc);
509
170
          if (!have_logvolid)
510
170
            have_logvolid = !blkid_probe_set_utf8_id_label(pr, "LOGICAL_VOLUME_ID",
511
170
                vd->type.logical.logvol_id.c, clen, enc);
512
170
        }
513
194
      }
514
697
    } else if (type == TAG_ID_IUVD) {
515
171
      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)) {
516
        /* UDF-2.60: 2.2.7.2.3: Field LVInfo1 could contain information such as Owner Name
517
         * More UDF generating tools set this field to person who creating the filesystem
518
         * therefore its meaning is similar to ISO9660 Publisher Identifier. So for
519
         * compatibility with iso9660 superblock code export this field via PUBLISHER_ID.
520
         */
521
33
        int enc = udf_cid_to_enc(vd->type.imp_use_volume.lvinfo1.cid);
522
33
        uint8_t clen = vd->type.imp_use_volume.lvinfo1.clen;
523
33
        if (clen > 0)
524
21
          --clen;
525
33
        if (clen > sizeof(vd->type.imp_use_volume.lvinfo1.c))
526
7
          clen = sizeof(vd->type.imp_use_volume.lvinfo1.c);
527
33
        if (enc != -1)
528
11
          have_publisherid = !blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID",
529
11
                vd->type.imp_use_volume.lvinfo1.c, clen, enc);
530
33
      }
531
171
    }
532
1.71k
    if (is_udf && have_volid && have_uuid && have_volsetid && have_logvolid && have_label && lvid_len && lvid_loc && have_applicationid && have_publisherid)
533
5
      break;
534
1.71k
  }
535
536
466
  if (!is_udf) {
537
    /* We detected some other ISO/IEC 13346 or ECMA-167 filesystem, not UDF */
538
220
    return 1;
539
220
  }
540
541
  /* Pick the first logical volume integrity descriptor and read UDF revision */
542
246
  if (lvid_loc && lvid_len >= sizeof(*vd)) {
543
215
    vd = (struct volume_descriptor *)
544
215
      blkid_probe_get_buffer(pr,
545
215
          (uint64_t) lvid_loc * bs,
546
215
          sizeof(*vd));
547
215
    if (!vd)
548
124
      return errno ? -errno : 1;
549
91
    type = le16_to_cpu(vd->tag.id);
550
91
    if (type == TAG_ID_LVID &&
551
60
        le32_to_cpu(vd->tag.location) == lvid_loc &&
552
51
        UDF_LVIDIU_LENGTH(*vd) >= sizeof(*lvidiu)) {
553
      /* ECMA-167 3/8.8.2: There is stored sequence of LVIDs and valid is just last
554
       * one. So correctly we should jump to next_lvid_location and read next LVID
555
       * until we find last one. This could be time consuming process and could
556
       * lead to scanning lot of disk blocks. Because we use LVID only for UDF
557
       * version, in the worst case we would report only wrong ID_FS_VERSION. */
558
48
      uint16_t lvidiu_udf_rev;
559
48
      lvidiu = (struct logical_vol_integ_descriptor_imp_use *)
560
48
        blkid_probe_get_buffer(pr,
561
48
            (uint64_t) lvid_loc * bs + UDF_LVIDIU_OFFSET(*vd),
562
48
            sizeof(*lvidiu));
563
48
      if (!lvidiu)
564
12
        return errno ? -errno : 1;
565
      /* UDF-2.60: 2. Basic Restrictions & Requirements:
566
       * The Minimum UDF Read Revision value shall be at most #0250
567
       * for all media with a UDF 2.60 file system.
568
       * Because some 2.60 implementations put 2.50 into both LVIDIU
569
       * fields and 2.60 into LVD, use maximal value from LVD,
570
       * Minimum UDF Read Revision and Minimum UDF Write Revision for
571
       * ID_FS_VERSION to distinguish between UDF 2.50 and UDF 2.60 discs. */
572
36
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_read_rev);
573
36
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
574
22
        udf_rev = lvidiu_udf_rev;
575
36
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_write_rev);
576
36
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
577
9
        udf_rev = lvidiu_udf_rev;
578
36
    }
579
91
  }
580
581
110
  if (udf_rev)
582
    /* UDF revision is stored as decimal number in hexadecimal format.
583
     * E.g. number 0x0150 is revision 1.50, number 0x0201 is revision 2.01. */
584
101
    blkid_probe_sprintf_version(pr, "%x.%02x", (unsigned int)(udf_rev >> 8), (unsigned int)(udf_rev & 0xFF));
585
586
110
  blkid_probe_set_fsblocksize(pr, bs);
587
110
  blkid_probe_set_block_size(pr, bs);
588
589
110
  return 0;
590
246
}
591
592
593
const struct blkid_idinfo udf_idinfo =
594
{
595
  .name   = "udf",
596
  .usage    = BLKID_USAGE_FILESYSTEM,
597
  .probefunc  = probe_udf,
598
  .flags    = BLKID_IDINFO_TOLERANT,
599
  .magics   =
600
  {
601
    /* These magics are generic to all ISO/IEC 13346 and ECMA-167 filesystems, not just UDF */
602
    { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
603
    { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
604
    { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
605
    { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
606
    { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
607
    { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
608
    { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" },
609
    { NULL }
610
  }
611
};