Coverage Report

Created: 2026-08-31 07:08

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.60k
#define is_charset_udf(charspec) ((charspec).type == 0 && strncmp((charspec).info, "OSTA Compressed Unicode", sizeof((charspec).info)) == 0)
23
24
1.00k
#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
2.31k
#define TAG_ID_PVD  1
141
836
#define TAG_ID_AVDP 2
142
879
#define TAG_ID_IUVD 4
143
1.72k
#define TAG_ID_LVD  6
144
2.35k
#define TAG_ID_TD   8
145
240
#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
5.04k
#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
51
#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
54
#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
253
{
170
253
  int enc;
171
253
  size_t i;
172
253
  size_t len;
173
253
  size_t clen;
174
253
  size_t nonhexpos;
175
253
  unsigned char buf[17];
176
177
253
  memset(buf, 0, sizeof(buf));
178
179
253
  clen = volset_id->clen;
180
253
  if (clen > 0)
181
238
    --clen;
182
253
  if (clen > sizeof(volset_id->c))
183
51
    clen = sizeof(volset_id->c);
184
185
253
  enc = udf_cid_to_enc(volset_id->cid);
186
253
  if (enc == -1)
187
25
    return -1;
188
189
228
  len = ul_encode_to_utf8(enc, buf, sizeof(buf), volset_id->c, clen);
190
228
  if (len < 8)
191
18
    return -1;
192
193
210
  nonhexpos = 16;
194
1.52k
  for (i = 0; i < 16; ++i) {
195
1.48k
    if (!isxdigit(buf[i])) {
196
167
      nonhexpos = i;
197
167
      break;
198
167
    }
199
1.48k
  }
200
201
210
  if (nonhexpos < 8) {
202
104
    snprintf((char *) uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
203
104
      buf[0], buf[1], buf[2], buf[3],
204
104
      buf[4], buf[5], buf[6], buf[7]);
205
106
  } else if (nonhexpos < 16) {
206
567
    for (i = 0; i < 8; ++i)
207
504
      uuid[i] = tolower(buf[i]);
208
63
    snprintf((char *) uuid + 8, 9, "%02x%02x%02x%02x",
209
63
      buf[8], buf[9], buf[10], buf[11]);
210
63
  } else {
211
731
    for (i = 0; i < 16; ++i)
212
688
      uuid[i] = tolower(buf[i]);
213
43
    uuid[16] = 0;
214
43
  }
215
216
210
  return 0;
217
228
}
218
219
static int probe_udf(blkid_probe pr,
220
    const struct blkid_idmag *mag __attribute__((__unused__)))
221
1.63k
{
222
1.63k
  struct volume_descriptor *vd;
223
1.63k
  struct volume_structure_descriptor *vsd;
224
1.63k
  struct logical_vol_integ_descriptor_imp_use *lvidiu;
225
1.63k
  uint32_t lvid_len = 0;
226
1.63k
  uint32_t lvid_loc = 0;
227
1.63k
  uint64_t s_off;
228
1.63k
  uint32_t bs;
229
1.63k
  uint32_t b;
230
1.63k
  uint16_t type;
231
1.63k
  uint32_t count;
232
1.63k
  uint32_t loc;
233
1.63k
  size_t i;
234
1.63k
  uint32_t vsd_len;
235
1.63k
  uint16_t udf_rev = 0;
236
1.63k
  int is_udf = 0;
237
1.63k
  int vsd_2048_valid = -1;
238
1.63k
  int have_label = 0;
239
1.63k
  int have_uuid = 0;
240
1.63k
  int have_logvolid = 0;
241
1.63k
  int have_volid = 0;
242
1.63k
  int have_volsetid = 0;
243
1.63k
  int have_applicationid = 0;
244
1.63k
  int have_publisherid = 0;
245
246
  /* Session offset */
247
1.63k
  if (blkid_probe_get_hint(pr, "session_offset", &s_off) < 0)
248
1.63k
    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
1.63k
  uint32_t pbs[] = { 0, 512, 1024, 2048, 4096 };
254
1.63k
  pbs[0] = blkid_probe_get_sectorsize(pr);
255
256
3.84k
  for (i = 0; i < ARRAY_SIZE(pbs); i++) {
257
    /* Do not try with block size same as sector size two times */
258
3.63k
    if (i != 0 && pbs[0] == pbs[i])
259
539
      continue;
260
261
    /* Do not try with block size which is not divisor of session offset */
262
3.09k
    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
3.09k
    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
3.09k
    if (s_off == 0 && vsd_len == 2048) {
273
2.64k
      if (vsd_2048_valid == 0)
274
888
        continue;
275
1.75k
      if (vsd_2048_valid == 1)
276
126
        goto anchor;
277
1.75k
    }
278
279
    /* Check for a Volume Structure Descriptor (VSD) */
280
5.04k
    for (b = 0; b < 64; b++) {
281
5.04k
      vsd = (struct volume_structure_descriptor *)
282
5.04k
        blkid_probe_get_buffer(pr,
283
5.04k
            s_off + UDF_VSD_OFFSET + b * vsd_len,
284
5.04k
            sizeof(*vsd));
285
5.04k
      if (!vsd)
286
465
        return errno ? -errno : 1;
287
4.57k
      if (vsd->id[0] == '\0')
288
364
        break;
289
4.21k
      if (memcmp(vsd->id, "NSR02", 5) == 0 ||
290
4.05k
          memcmp(vsd->id, "NSR03", 5) == 0)
291
957
        goto anchor;
292
3.25k
      else if (memcmp(vsd->id, "BEA01", 5) != 0 &&
293
2.37k
               memcmp(vsd->id, "BOOT2", 5) != 0 &&
294
2.05k
               memcmp(vsd->id, "CD001", 5) != 0 &&
295
752
               memcmp(vsd->id, "CDW02", 5) != 0 &&
296
506
               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
285
        break;
305
4.21k
    }
306
307
655
    if (s_off == 0 && vsd_len == 2048)
308
444
      vsd_2048_valid = 0;
309
310
    /* NSR was not found, try with next block size */
311
655
    continue;
312
313
1.08k
anchor:
314
1.08k
    if (s_off == 0 && vsd_len == 2048)
315
1.08k
      vsd_2048_valid = 1;
316
317
    /* Read Anchor Volume Descriptor (AVDP), detect block size */
318
1.08k
    vd = (struct volume_descriptor *)
319
1.08k
      blkid_probe_get_buffer(pr, s_off + 256 * pbs[i], sizeof(*vd));
320
1.08k
    if (!vd)
321
36
      return errno ? -errno : 1;
322
323
    /* Check that we read correct sector and detected correct block size */
324
1.04k
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 256) {
325
822
      type = le16_to_cpu(vd->tag.id);
326
822
      if (type == TAG_ID_AVDP)
327
789
        goto real_blksz;
328
822
    }
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
258
    vd = (struct volume_descriptor *)
333
258
      blkid_probe_get_buffer(pr, s_off + 512 * pbs[i], sizeof(*vd));
334
258
    if (!vd)
335
130
      return errno ? -errno : 1;
336
337
128
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 512) {
338
14
      type = le16_to_cpu(vd->tag.id);
339
14
      if (type == TAG_ID_AVDP)
340
2
        goto real_blksz;
341
14
    }
342
343
128
  }
344
211
  return 1;
345
346
791
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
791
  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
791
  count = le32_to_cpu(vd->type.anchor.length) / bs;
357
791
  if (count > 64)
358
233
    count = 64;
359
791
  loc = le32_to_cpu(vd->type.anchor.location);
360
361
  /* pick the primary descriptor from the list and read UDF identifiers */
362
3.09k
  for (b = 0; b < count; b++) {
363
3.08k
    vd = (struct volume_descriptor *)
364
3.08k
      blkid_probe_get_buffer(pr,
365
3.08k
          ((uint64_t) loc + b) * bs,
366
3.08k
          sizeof(*vd));
367
3.08k
    if (!vd)
368
64
      return errno ? -errno : 1;
369
3.02k
    type = le16_to_cpu(vd->tag.id);
370
3.02k
    if (type == 0)
371
260
      break;
372
2.76k
    if (le32_to_cpu(vd->tag.location) != loc + b)
373
409
      break;
374
2.35k
    if (type == TAG_ID_TD)
375
41
      break;
376
2.31k
    if (type == TAG_ID_PVD) {
377
592
      if (!have_volid && is_charset_udf(vd->type.primary.desc_charset)) {
378
253
        int enc = udf_cid_to_enc(vd->type.primary.ident.cid);
379
253
        uint8_t clen = vd->type.primary.ident.clen;
380
253
        if (clen > 0)
381
153
          --clen;
382
253
        if (clen > sizeof(vd->type.primary.ident.c))
383
27
          clen = sizeof(vd->type.primary.ident.c);
384
253
        if (enc != -1)
385
226
          have_volid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_ID",
386
226
              vd->type.primary.ident.c, clen, enc);
387
253
      }
388
592
      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
253
        unsigned char uuid[17];
419
253
        if (gen_uuid_from_volset_id(uuid, &vd->type.primary.volset_id) == 0)
420
210
          have_uuid = !blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
421
253
      }
422
592
      if (!have_volsetid && is_charset_udf(vd->type.primary.desc_charset)) {
423
253
        int enc = udf_cid_to_enc(vd->type.primary.volset_id.cid);
424
253
        uint8_t clen = vd->type.primary.volset_id.clen;
425
253
        if (clen > 0)
426
238
          --clen;
427
253
        if (clen > sizeof(vd->type.primary.volset_id.c))
428
51
          clen = sizeof(vd->type.primary.volset_id.c);
429
253
        if (enc != -1)
430
228
          have_volsetid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID",
431
228
              vd->type.primary.volset_id.c, clen, enc);
432
253
      }
433
592
      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
570
        const unsigned char *app_id = (const unsigned char *)vd->type.primary.app_id;
436
570
        size_t app_id_len = strnlen(vd->type.primary.app_id, sizeof(vd->type.primary.app_id));
437
570
        if (app_id_len > 0 && app_id[0] == '*') {
438
196
          app_id++;
439
196
          app_id_len--;
440
196
        }
441
        /* When Application Identifier is not set then use Developer ID from Implementation Identifier */
442
570
        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
270
          app_id = (const unsigned char *)vd->type.primary.imp_id;
445
270
          app_id_len = strnlen(vd->type.primary.imp_id, sizeof(vd->type.primary.imp_id));
446
270
          if (app_id_len > 0 && app_id[0] == '*') {
447
30
            app_id++;
448
30
            app_id_len--;
449
30
          }
450
270
        }
451
570
        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
430
          have_applicationid = !blkid_probe_set_id_label(pr, "APPLICATION_ID", app_id, app_id_len);
454
430
        }
455
570
      }
456
1.72k
    } else if (type == TAG_ID_LVD) {
457
841
      if (!lvid_len || !lvid_loc) {
458
723
        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
723
        if (num_partition_maps) {
461
601
          lvid_len = le32_to_cpu(vd->type.logical.lvid_length);
462
601
          lvid_loc = le32_to_cpu(vd->type.logical.lvid_location);
463
601
        }
464
723
      }
465
841
      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
750
        if (strncmp(vd->type.logical.domain_id, "*OSTA UDF Compliant", sizeof(vd->type.logical.domain_id)) == 0) {
470
304
          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
304
          if (!udf_rev)
474
304
            udf_rev = le16_to_cpu(vd->type.logical.udf_rev);
475
304
        }
476
750
      }
477
841
      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
210
        int enc = udf_cid_to_enc(vd->type.logical.logvol_id.cid);
505
210
        uint8_t clen = vd->type.logical.logvol_id.clen;
506
210
        if (clen > 0)
507
143
          --clen;
508
210
        if (clen > sizeof(vd->type.logical.logvol_id.c))
509
14
          clen = sizeof(vd->type.logical.logvol_id.c);
510
210
        if (enc != -1) {
511
187
          if (!have_label)
512
187
            have_label = !blkid_probe_set_utf8label(pr,
513
187
                vd->type.logical.logvol_id.c, clen, enc);
514
187
          if (!have_logvolid)
515
187
            have_logvolid = !blkid_probe_set_utf8_id_label(pr, "LOGICAL_VOLUME_ID",
516
187
                vd->type.logical.logvol_id.c, clen, enc);
517
187
        }
518
210
      }
519
879
    } else if (type == TAG_ID_IUVD) {
520
228
      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
31
        int enc = udf_cid_to_enc(vd->type.imp_use_volume.lvinfo1.cid);
527
31
        uint8_t clen = vd->type.imp_use_volume.lvinfo1.clen;
528
31
        if (clen > 0)
529
23
          --clen;
530
31
        if (clen > sizeof(vd->type.imp_use_volume.lvinfo1.c))
531
9
          clen = sizeof(vd->type.imp_use_volume.lvinfo1.c);
532
31
        if (enc != -1)
533
19
          have_publisherid = !blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID",
534
19
                vd->type.imp_use_volume.lvinfo1.c, clen, enc);
535
31
      }
536
228
    }
537
2.31k
    if (is_udf && have_volid && have_uuid && have_volsetid && have_logvolid && have_label && lvid_len && lvid_loc && have_applicationid && have_publisherid)
538
10
      break;
539
2.31k
  }
540
541
727
  if (!is_udf) {
542
    /* We detected some other ISO/IEC 13346 or ECMA-167 filesystem, not UDF */
543
445
    return 1;
544
445
  }
545
546
  /* Pick the first logical volume integrity descriptor and read UDF revision */
547
282
  if (lvid_loc && lvid_len >= sizeof(*vd)) {
548
242
    vd = (struct volume_descriptor *)
549
242
      blkid_probe_get_buffer(pr,
550
242
          (uint64_t) lvid_loc * bs,
551
242
          sizeof(*vd));
552
242
    if (!vd)
553
122
      return errno ? -errno : 1;
554
120
    type = le16_to_cpu(vd->tag.id);
555
120
    if (type == TAG_ID_LVID &&
556
82
        le32_to_cpu(vd->tag.location) == lvid_loc &&
557
54
        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
51
      uint16_t lvidiu_udf_rev;
564
51
      lvidiu = (struct logical_vol_integ_descriptor_imp_use *)
565
51
        blkid_probe_get_buffer(pr,
566
51
            (uint64_t) lvid_loc * bs + UDF_LVIDIU_OFFSET(*vd),
567
51
            sizeof(*lvidiu));
568
51
      if (!lvidiu)
569
10
        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
41
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_read_rev);
578
41
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
579
17
        udf_rev = lvidiu_udf_rev;
580
41
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_write_rev);
581
41
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
582
10
        udf_rev = lvidiu_udf_rev;
583
41
    }
584
120
  }
585
586
150
  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
131
    blkid_probe_sprintf_version(pr, "%x.%02x", (unsigned int)(udf_rev >> 8), (unsigned int)(udf_rev & 0xFF));
590
591
150
  blkid_probe_set_fsblocksize(pr, bs);
592
150
  blkid_probe_set_block_size(pr, bs);
593
594
150
  return 0;
595
282
}
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
};