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/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
27
#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
26
#define TAG_ID_PVD  1
141
76
#define TAG_ID_AVDP 2
142
17
#define TAG_ID_IUVD 4
143
17
#define TAG_ID_LVD  6
144
26
#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.54k
#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) + 2 * 4 * 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
462
{
222
462
  struct volume_descriptor *vd;
223
462
  struct volume_structure_descriptor *vsd;
224
462
  struct logical_vol_integ_descriptor_imp_use *lvidiu;
225
462
  uint32_t lvid_len = 0;
226
462
  uint32_t lvid_loc = 0;
227
462
  uint64_t s_off;
228
462
  uint32_t bs;
229
462
  uint32_t b;
230
462
  uint16_t type;
231
462
  uint32_t count;
232
462
  uint32_t loc;
233
462
  size_t i;
234
462
  uint32_t vsd_len;
235
462
  uint16_t udf_rev = 0;
236
462
  int is_udf = 0;
237
462
  int vsd_2048_valid = -1;
238
462
  int have_label = 0;
239
462
  int have_uuid = 0;
240
462
  int have_logvolid = 0;
241
462
  int have_volid = 0;
242
462
  int have_volsetid = 0;
243
462
  int have_applicationid = 0;
244
462
  int have_publisherid = 0;
245
246
  /* Session offset */
247
462
  if (blkid_probe_get_hint(pr, "session_offset", &s_off) < 0)
248
462
    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
462
  uint32_t pbs[] = { 0, 512, 1024, 2048, 4096 };
254
462
  pbs[0] = blkid_probe_get_sectorsize(pr);
255
256
2.57k
  for (i = 0; i < ARRAY_SIZE(pbs); i++) {
257
    /* Do not try with block size same as sector size two times */
258
2.17k
    if (i != 0 && pbs[0] == pbs[i])
259
462
      continue;
260
261
    /* Do not try with block size which is not divisor of session offset */
262
1.71k
    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.71k
    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.71k
    if (s_off == 0 && vsd_len == 2048) {
273
1.31k
      if (vsd_2048_valid == 0)
274
568
        continue;
275
751
      if (vsd_2048_valid == 1)
276
289
        goto anchor;
277
751
    }
278
279
    /* Check for a Volume Structure Descriptor (VSD) */
280
1.54k
    for (b = 0; b < 64; b++) {
281
1.54k
      vsd = (struct volume_structure_descriptor *)
282
1.54k
        blkid_probe_get_buffer(pr,
283
1.54k
            s_off + UDF_VSD_OFFSET + b * vsd_len,
284
1.54k
            sizeof(*vsd));
285
1.54k
      if (!vsd)
286
0
        return errno ? -errno : 1;
287
1.54k
      if (vsd->id[0] == '\0')
288
167
        break;
289
1.37k
      if (memcmp(vsd->id, "NSR02", 5) == 0 ||
290
1.24k
          memcmp(vsd->id, "NSR03", 5) == 0)
291
291
        goto anchor;
292
1.08k
      else if (memcmp(vsd->id, "BEA01", 5) != 0 &&
293
1.00k
               memcmp(vsd->id, "BOOT2", 5) != 0 &&
294
971
               memcmp(vsd->id, "CD001", 5) != 0 &&
295
475
               memcmp(vsd->id, "CDW02", 5) != 0 &&
296
446
               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
399
        break;
305
1.37k
    }
306
307
566
    if (s_off == 0 && vsd_len == 2048)
308
284
      vsd_2048_valid = 0;
309
310
    /* NSR was not found, try with next block size */
311
566
    continue;
312
313
580
anchor:
314
580
    if (s_off == 0 && vsd_len == 2048)
315
467
      vsd_2048_valid = 1;
316
317
    /* Read Anchor Volume Descriptor (AVDP), detect block size */
318
580
    vd = (struct volume_descriptor *)
319
580
      blkid_probe_get_buffer(pr, s_off + 256 * pbs[i], sizeof(*vd));
320
580
    if (!vd)
321
0
      return errno ? -errno : 1;
322
323
    /* Check that we read correct sector and detected correct block size */
324
580
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 256) {
325
70
      type = le16_to_cpu(vd->tag.id);
326
70
      if (type == TAG_ID_AVDP)
327
67
        goto real_blksz;
328
70
    }
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
513
    vd = (struct volume_descriptor *)
333
513
      blkid_probe_get_buffer(pr, s_off + 512 * pbs[i], sizeof(*vd));
334
513
    if (!vd)
335
0
      return errno ? -errno : 1;
336
337
513
    if (le32_to_cpu(vd->tag.location) == s_off / pbs[i] + 512) {
338
6
      type = le16_to_cpu(vd->tag.id);
339
6
      if (type == TAG_ID_AVDP)
340
0
        goto real_blksz;
341
6
    }
342
343
513
  }
344
395
  return 1;
345
346
67
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
67
  bs = pbs[i];
351
352
  /* get descriptor list address and block count */
353
67
  count = le32_to_cpu(vd->type.anchor.length) / bs;
354
67
  loc = le32_to_cpu(vd->type.anchor.location);
355
356
  /* pick the primary descriptor from the list and read UDF identifiers */
357
93
  for (b = 0; b < count; b++) {
358
68
    vd = (struct volume_descriptor *)
359
68
      blkid_probe_get_buffer(pr,
360
68
          (uint64_t) (loc + b) * bs,
361
68
          sizeof(*vd));
362
68
    if (!vd)
363
3
      return errno ? -errno : 1;
364
65
    type = le16_to_cpu(vd->tag.id);
365
65
    if (type == 0)
366
3
      break;
367
62
    if (le32_to_cpu(vd->tag.location) != loc + b)
368
36
      break;
369
26
    if (type == TAG_ID_TD)
370
0
      break;
371
26
    if (type == TAG_ID_PVD) {
372
9
      if (!have_volid && is_charset_udf(vd->type.primary.desc_charset)) {
373
0
        int enc = udf_cid_to_enc(vd->type.primary.ident.cid);
374
0
        uint8_t clen = vd->type.primary.ident.clen;
375
0
        if (clen > 0)
376
0
          --clen;
377
0
        if (clen > sizeof(vd->type.primary.ident.c))
378
0
          clen = sizeof(vd->type.primary.ident.c);
379
0
        if (enc != -1)
380
0
          have_volid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_ID",
381
0
              vd->type.primary.ident.c, clen, enc);
382
0
      }
383
9
      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
0
        unsigned char uuid[17];
414
0
        if (gen_uuid_from_volset_id(uuid, &vd->type.primary.volset_id) == 0)
415
0
          have_uuid = !blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid));
416
0
      }
417
9
      if (!have_volsetid && is_charset_udf(vd->type.primary.desc_charset)) {
418
0
        int enc = udf_cid_to_enc(vd->type.primary.volset_id.cid);
419
0
        uint8_t clen = vd->type.primary.volset_id.clen;
420
0
        if (clen > 0)
421
0
          --clen;
422
0
        if (clen > sizeof(vd->type.primary.volset_id.c))
423
0
          clen = sizeof(vd->type.primary.volset_id.c);
424
0
        if (enc != -1)
425
0
          have_volsetid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID",
426
0
              vd->type.primary.volset_id.c, clen, enc);
427
0
      }
428
9
      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
9
        const unsigned char *app_id = (const unsigned char *)vd->type.primary.app_id;
431
9
        size_t app_id_len = strnlen(vd->type.primary.app_id, sizeof(vd->type.primary.app_id));
432
9
        if (app_id_len > 0 && app_id[0] == '*') {
433
0
          app_id++;
434
0
          app_id_len--;
435
0
        }
436
        /* When Application Identifier is not set then use Developer ID from Implementation Identifier */
437
9
        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
6
          app_id = (const unsigned char *)vd->type.primary.imp_id;
440
6
          app_id_len = strnlen(vd->type.primary.imp_id, sizeof(vd->type.primary.imp_id));
441
6
          if (app_id_len > 0 && app_id[0] == '*') {
442
0
            app_id++;
443
0
            app_id_len--;
444
0
          }
445
6
        }
446
9
        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
6
          have_applicationid = !blkid_probe_set_id_label(pr, "APPLICATION_ID", app_id, app_id_len);
449
6
        }
450
9
      }
451
17
    } else if (type == TAG_ID_LVD) {
452
0
      if (!lvid_len || !lvid_loc) {
453
0
        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
0
        if (num_partition_maps) {
456
0
          lvid_len = le32_to_cpu(vd->type.logical.lvid_length);
457
0
          lvid_loc = le32_to_cpu(vd->type.logical.lvid_location);
458
0
        }
459
0
      }
460
0
      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
0
        if (strncmp(vd->type.logical.domain_id, "*OSTA UDF Compliant", sizeof(vd->type.logical.domain_id)) == 0) {
465
0
          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
0
          if (!udf_rev)
469
0
            udf_rev = le16_to_cpu(vd->type.logical.udf_rev);
470
0
        }
471
0
      }
472
0
      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
0
        int enc = udf_cid_to_enc(vd->type.logical.logvol_id.cid);
500
0
        uint8_t clen = vd->type.logical.logvol_id.clen;
501
0
        if (clen > 0)
502
0
          --clen;
503
0
        if (clen > sizeof(vd->type.logical.logvol_id.c))
504
0
          clen = sizeof(vd->type.logical.logvol_id.c);
505
0
        if (enc != -1) {
506
0
          if (!have_label)
507
0
            have_label = !blkid_probe_set_utf8label(pr,
508
0
                vd->type.logical.logvol_id.c, clen, enc);
509
0
          if (!have_logvolid)
510
0
            have_logvolid = !blkid_probe_set_utf8_id_label(pr, "LOGICAL_VOLUME_ID",
511
0
                vd->type.logical.logvol_id.c, clen, enc);
512
0
        }
513
0
      }
514
17
    } else if (type == TAG_ID_IUVD) {
515
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)) {
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
0
        int enc = udf_cid_to_enc(vd->type.imp_use_volume.lvinfo1.cid);
522
0
        uint8_t clen = vd->type.imp_use_volume.lvinfo1.clen;
523
0
        if (clen > 0)
524
0
          --clen;
525
0
        if (clen > sizeof(vd->type.imp_use_volume.lvinfo1.c))
526
0
          clen = sizeof(vd->type.imp_use_volume.lvinfo1.c);
527
0
        if (enc != -1)
528
0
          have_publisherid = !blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID",
529
0
                vd->type.imp_use_volume.lvinfo1.c, clen, enc);
530
0
      }
531
3
    }
532
26
    if (is_udf && have_volid && have_uuid && have_volsetid && have_logvolid && have_label && lvid_len && lvid_loc && have_applicationid && have_publisherid)
533
0
      break;
534
26
  }
535
536
64
  if (!is_udf) {
537
    /* We detected some other ISO/IEC 13346 or ECMA-167 filesystem, not UDF */
538
64
    return 1;
539
64
  }
540
541
  /* Pick the first logical volume integrity descriptor and read UDF revision */
542
0
  if (lvid_loc && lvid_len >= sizeof(*vd)) {
543
0
    vd = (struct volume_descriptor *)
544
0
      blkid_probe_get_buffer(pr,
545
0
          (uint64_t) lvid_loc * bs,
546
0
          sizeof(*vd));
547
0
    if (!vd)
548
0
      return errno ? -errno : 1;
549
0
    type = le16_to_cpu(vd->tag.id);
550
0
    if (type == TAG_ID_LVID &&
551
0
        le32_to_cpu(vd->tag.location) == lvid_loc &&
552
0
        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
0
      uint16_t lvidiu_udf_rev;
559
0
      lvidiu = (struct logical_vol_integ_descriptor_imp_use *)
560
0
        blkid_probe_get_buffer(pr,
561
0
            (uint64_t) lvid_loc * bs + UDF_LVIDIU_OFFSET(*vd),
562
0
            sizeof(*lvidiu));
563
0
      if (!lvidiu)
564
0
        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
0
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_read_rev);
573
0
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
574
0
        udf_rev = lvidiu_udf_rev;
575
0
      lvidiu_udf_rev = le16_to_cpu(lvidiu->min_udf_write_rev);
576
0
      if (lvidiu_udf_rev && udf_rev < lvidiu_udf_rev)
577
0
        udf_rev = lvidiu_udf_rev;
578
0
    }
579
0
  }
580
581
0
  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
0
    blkid_probe_sprintf_version(pr, "%x.%02x", (unsigned int)(udf_rev >> 8), (unsigned int)(udf_rev & 0xFF));
585
586
0
  blkid_probe_set_fsblocksize(pr, bs);
587
0
  blkid_probe_set_block_size(pr, bs);
588
589
0
  return 0;
590
0
}
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
};