~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/fs/udf.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* udf.c - Universal Disk Format filesystem.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/err.h>
 
21
#include <grub/file.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/misc.h>
 
24
#include <grub/disk.h>
 
25
#include <grub/dl.h>
 
26
#include <grub/types.h>
 
27
#include <grub/fshelp.h>
 
28
#include <grub/charset.h>
 
29
 
 
30
#define GRUB_UDF_MAX_PDS                2
 
31
#define GRUB_UDF_MAX_PMS                6
 
32
 
 
33
#define U16                             grub_le_to_cpu16
 
34
#define U32                             grub_le_to_cpu32
 
35
#define U64                             grub_le_to_cpu64
 
36
 
 
37
#define GRUB_UDF_TAG_IDENT_PVD          0x0001
 
38
#define GRUB_UDF_TAG_IDENT_AVDP         0x0002
 
39
#define GRUB_UDF_TAG_IDENT_VDP          0x0003
 
40
#define GRUB_UDF_TAG_IDENT_IUVD         0x0004
 
41
#define GRUB_UDF_TAG_IDENT_PD           0x0005
 
42
#define GRUB_UDF_TAG_IDENT_LVD          0x0006
 
43
#define GRUB_UDF_TAG_IDENT_USD          0x0007
 
44
#define GRUB_UDF_TAG_IDENT_TD           0x0008
 
45
#define GRUB_UDF_TAG_IDENT_LVID         0x0009
 
46
 
 
47
#define GRUB_UDF_TAG_IDENT_FSD          0x0100
 
48
#define GRUB_UDF_TAG_IDENT_FID          0x0101
 
49
#define GRUB_UDF_TAG_IDENT_AED          0x0102
 
50
#define GRUB_UDF_TAG_IDENT_IE           0x0103
 
51
#define GRUB_UDF_TAG_IDENT_TE           0x0104
 
52
#define GRUB_UDF_TAG_IDENT_FE           0x0105
 
53
#define GRUB_UDF_TAG_IDENT_EAHD         0x0106
 
54
#define GRUB_UDF_TAG_IDENT_USE          0x0107
 
55
#define GRUB_UDF_TAG_IDENT_SBD          0x0108
 
56
#define GRUB_UDF_TAG_IDENT_PIE          0x0109
 
57
#define GRUB_UDF_TAG_IDENT_EFE          0x010A
 
58
 
 
59
#define GRUB_UDF_ICBTAG_TYPE_UNDEF      0x00
 
60
#define GRUB_UDF_ICBTAG_TYPE_USE        0x01
 
61
#define GRUB_UDF_ICBTAG_TYPE_PIE        0x02
 
62
#define GRUB_UDF_ICBTAG_TYPE_IE         0x03
 
63
#define GRUB_UDF_ICBTAG_TYPE_DIRECTORY  0x04
 
64
#define GRUB_UDF_ICBTAG_TYPE_REGULAR    0x05
 
65
#define GRUB_UDF_ICBTAG_TYPE_BLOCK      0x06
 
66
#define GRUB_UDF_ICBTAG_TYPE_CHAR       0x07
 
67
#define GRUB_UDF_ICBTAG_TYPE_EA         0x08
 
68
#define GRUB_UDF_ICBTAG_TYPE_FIFO       0x09
 
69
#define GRUB_UDF_ICBTAG_TYPE_SOCKET     0x0A
 
70
#define GRUB_UDF_ICBTAG_TYPE_TE         0x0B
 
71
#define GRUB_UDF_ICBTAG_TYPE_SYMLINK    0x0C
 
72
#define GRUB_UDF_ICBTAG_TYPE_STREAMDIR  0x0D
 
73
 
 
74
#define GRUB_UDF_ICBTAG_FLAG_AD_MASK    0x0007
 
75
#define GRUB_UDF_ICBTAG_FLAG_AD_SHORT   0x0000
 
76
#define GRUB_UDF_ICBTAG_FLAG_AD_LONG    0x0001
 
77
#define GRUB_UDF_ICBTAG_FLAG_AD_EXT     0x0002
 
78
#define GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB  0x0003
 
79
 
 
80
#define GRUB_UDF_EXT_NORMAL             0x00000000
 
81
#define GRUB_UDF_EXT_NREC_ALLOC         0x40000000
 
82
#define GRUB_UDF_EXT_NREC_NALLOC        0x80000000
 
83
#define GRUB_UDF_EXT_MASK               0xC0000000
 
84
 
 
85
#define GRUB_UDF_FID_CHAR_HIDDEN        0x01
 
86
#define GRUB_UDF_FID_CHAR_DIRECTORY     0x02
 
87
#define GRUB_UDF_FID_CHAR_DELETED       0x04
 
88
#define GRUB_UDF_FID_CHAR_PARENT        0x08
 
89
#define GRUB_UDF_FID_CHAR_METADATA      0x10
 
90
 
 
91
#define GRUB_UDF_STD_IDENT_BEA01        "BEA01"
 
92
#define GRUB_UDF_STD_IDENT_BOOT2        "BOOT2"
 
93
#define GRUB_UDF_STD_IDENT_CD001        "CD001"
 
94
#define GRUB_UDF_STD_IDENT_CDW02        "CDW02"
 
95
#define GRUB_UDF_STD_IDENT_NSR02        "NSR02"
 
96
#define GRUB_UDF_STD_IDENT_NSR03        "NSR03"
 
97
#define GRUB_UDF_STD_IDENT_TEA01        "TEA01"
 
98
 
 
99
#define GRUB_UDF_CHARSPEC_TYPE_CS0      0x00
 
100
#define GRUB_UDF_CHARSPEC_TYPE_CS1      0x01
 
101
#define GRUB_UDF_CHARSPEC_TYPE_CS2      0x02
 
102
#define GRUB_UDF_CHARSPEC_TYPE_CS3      0x03
 
103
#define GRUB_UDF_CHARSPEC_TYPE_CS4      0x04
 
104
#define GRUB_UDF_CHARSPEC_TYPE_CS5      0x05
 
105
#define GRUB_UDF_CHARSPEC_TYPE_CS6      0x06
 
106
#define GRUB_UDF_CHARSPEC_TYPE_CS7      0x07
 
107
#define GRUB_UDF_CHARSPEC_TYPE_CS8      0x08
 
108
 
 
109
#define GRUB_UDF_PARTMAP_TYPE_1         1
 
110
#define GRUB_UDF_PARTMAP_TYPE_2         2
 
111
 
 
112
struct grub_udf_lb_addr
 
113
{
 
114
  grub_uint32_t block_num;
 
115
  grub_uint16_t part_ref;
 
116
} __attribute__ ((packed));
 
117
 
 
118
struct grub_udf_short_ad
 
119
{
 
120
  grub_uint32_t length;
 
121
  grub_uint32_t position;
 
122
} __attribute__ ((packed));
 
123
 
 
124
struct grub_udf_long_ad
 
125
{
 
126
  grub_uint32_t length;
 
127
  struct grub_udf_lb_addr block;
 
128
  grub_uint8_t imp_use[6];
 
129
} __attribute__ ((packed));
 
130
 
 
131
struct grub_udf_extent_ad
 
132
{
 
133
  grub_uint32_t length;
 
134
  grub_uint32_t start;
 
135
} __attribute__ ((packed));
 
136
 
 
137
struct grub_udf_charspec
 
138
{
 
139
  grub_uint8_t charset_type;
 
140
  grub_uint8_t charset_info[63];
 
141
} __attribute__ ((packed));
 
142
 
 
143
struct grub_udf_timestamp
 
144
{
 
145
  grub_uint16_t type_and_timezone;
 
146
  grub_uint16_t year;
 
147
  grub_uint8_t month;
 
148
  grub_uint8_t day;
 
149
  grub_uint8_t hour;
 
150
  grub_uint8_t minute;
 
151
  grub_uint8_t second;
 
152
  grub_uint8_t centi_seconds;
 
153
  grub_uint8_t hundreds_of_micro_seconds;
 
154
  grub_uint8_t micro_seconds;
 
155
} __attribute__ ((packed));
 
156
 
 
157
struct grub_udf_regid
 
158
{
 
159
  grub_uint8_t flags;
 
160
  grub_uint8_t ident[23];
 
161
  grub_uint8_t ident_suffix[8];
 
162
} __attribute__ ((packed));
 
163
 
 
164
struct grub_udf_tag
 
165
{
 
166
  grub_uint16_t tag_ident;
 
167
  grub_uint16_t desc_version;
 
168
  grub_uint8_t tag_checksum;
 
169
  grub_uint8_t reserved;
 
170
  grub_uint16_t tag_serial_number;
 
171
  grub_uint16_t desc_crc;
 
172
  grub_uint16_t desc_crc_length;
 
173
  grub_uint32_t tag_location;
 
174
} __attribute__ ((packed));
 
175
 
 
176
struct grub_udf_fileset
 
177
{
 
178
  struct grub_udf_tag tag;
 
179
  struct grub_udf_timestamp datetime;
 
180
  grub_uint16_t interchange_level;
 
181
  grub_uint16_t max_interchange_level;
 
182
  grub_uint32_t charset_list;
 
183
  grub_uint32_t max_charset_list;
 
184
  grub_uint32_t fileset_num;
 
185
  grub_uint32_t fileset_desc_num;
 
186
  struct grub_udf_charspec vol_charset;
 
187
  grub_uint8_t vol_ident[128];
 
188
  struct grub_udf_charspec fileset_charset;
 
189
  grub_uint8_t fileset_ident[32];
 
190
  grub_uint8_t copyright_file_ident[32];
 
191
  grub_uint8_t abstract_file_ident[32];
 
192
  struct grub_udf_long_ad root_icb;
 
193
  struct grub_udf_regid domain_ident;
 
194
  struct grub_udf_long_ad next_ext;
 
195
  struct grub_udf_long_ad streamdir_icb;
 
196
} __attribute__ ((packed));
 
197
 
 
198
struct grub_udf_icbtag
 
199
{
 
200
  grub_uint32_t prior_recorded_num_direct_entries;
 
201
  grub_uint16_t strategy_type;
 
202
  grub_uint16_t strategy_parameter;
 
203
  grub_uint16_t num_entries;
 
204
  grub_uint8_t reserved;
 
205
  grub_uint8_t file_type;
 
206
  struct grub_udf_lb_addr parent_idb;
 
207
  grub_uint16_t flags;
 
208
} __attribute__ ((packed));
 
209
 
 
210
struct grub_udf_file_ident
 
211
{
 
212
  struct grub_udf_tag tag;
 
213
  grub_uint16_t version_num;
 
214
  grub_uint8_t characteristics;
 
215
  grub_uint8_t file_ident_length;
 
216
  struct grub_udf_long_ad icb;
 
217
  grub_uint16_t imp_use_length;
 
218
} __attribute__ ((packed));
 
219
 
 
220
struct grub_udf_file_entry
 
221
{
 
222
  struct grub_udf_tag tag;
 
223
  struct grub_udf_icbtag icbtag;
 
224
  grub_uint32_t uid;
 
225
  grub_uint32_t gid;
 
226
  grub_uint32_t permissions;
 
227
  grub_uint16_t link_count;
 
228
  grub_uint8_t record_format;
 
229
  grub_uint8_t record_display_attr;
 
230
  grub_uint32_t record_length;
 
231
  grub_uint64_t file_size;
 
232
  grub_uint64_t blocks_recorded;
 
233
  struct grub_udf_timestamp access_time;
 
234
  struct grub_udf_timestamp modification_time;
 
235
  struct grub_udf_timestamp attr_time;
 
236
  grub_uint32_t checkpoint;
 
237
  struct grub_udf_long_ad extended_attr_idb;
 
238
  struct grub_udf_regid imp_ident;
 
239
  grub_uint64_t unique_id;
 
240
  grub_uint32_t ext_attr_length;
 
241
  grub_uint32_t alloc_descs_length;
 
242
  grub_uint8_t ext_attr[1872];
 
243
} __attribute__ ((packed));
 
244
 
 
245
struct grub_udf_extended_file_entry
 
246
{
 
247
  struct grub_udf_tag tag;
 
248
  struct grub_udf_icbtag icbtag;
 
249
  grub_uint32_t uid;
 
250
  grub_uint32_t gid;
 
251
  grub_uint32_t permissions;
 
252
  grub_uint16_t link_count;
 
253
  grub_uint8_t record_format;
 
254
  grub_uint8_t record_display_attr;
 
255
  grub_uint32_t record_length;
 
256
  grub_uint64_t file_size;
 
257
  grub_uint64_t object_size;
 
258
  grub_uint64_t blocks_recorded;
 
259
  struct grub_udf_timestamp access_time;
 
260
  struct grub_udf_timestamp modification_time;
 
261
  struct grub_udf_timestamp create_time;
 
262
  struct grub_udf_timestamp attr_time;
 
263
  grub_uint32_t checkpoint;
 
264
  grub_uint32_t reserved;
 
265
  struct grub_udf_long_ad extended_attr_icb;
 
266
  struct grub_udf_long_ad streamdir_icb;
 
267
  struct grub_udf_regid imp_ident;
 
268
  grub_uint64_t unique_id;
 
269
  grub_uint32_t ext_attr_length;
 
270
  grub_uint32_t alloc_descs_length;
 
271
  grub_uint8_t ext_attr[1832];
 
272
} __attribute__ ((packed));
 
273
 
 
274
struct grub_udf_vrs
 
275
{
 
276
  grub_uint8_t type;
 
277
  grub_uint8_t magic[5];
 
278
  grub_uint8_t version;
 
279
} __attribute__ ((packed));
 
280
 
 
281
struct grub_udf_avdp
 
282
{
 
283
  struct grub_udf_tag tag;
 
284
  struct grub_udf_extent_ad vds;
 
285
} __attribute__ ((packed));
 
286
 
 
287
struct grub_udf_pd
 
288
{
 
289
  struct grub_udf_tag tag;
 
290
  grub_uint32_t seq_num;
 
291
  grub_uint16_t flags;
 
292
  grub_uint16_t part_num;
 
293
  struct grub_udf_regid contents;
 
294
  grub_uint8_t contents_use[128];
 
295
  grub_uint32_t access_type;
 
296
  grub_uint32_t start;
 
297
  grub_uint32_t length;
 
298
} __attribute__ ((packed));
 
299
 
 
300
struct grub_udf_partmap
 
301
{
 
302
  grub_uint8_t type;
 
303
  grub_uint8_t length;
 
304
  union
 
305
  {
 
306
    struct
 
307
    {
 
308
      grub_uint16_t seq_num;
 
309
      grub_uint16_t part_num;
 
310
    } type1;
 
311
 
 
312
    struct
 
313
    {
 
314
      grub_uint8_t ident[62];
 
315
    } type2;
 
316
  };
 
317
};
 
318
 
 
319
struct grub_udf_lvd
 
320
{
 
321
  struct grub_udf_tag tag;
 
322
  grub_uint32_t seq_num;
 
323
  struct grub_udf_charspec charset;
 
324
  grub_uint8_t ident[128];
 
325
  grub_uint32_t bsize;
 
326
  struct grub_udf_regid domain_ident;
 
327
  struct grub_udf_long_ad root_fileset;
 
328
  grub_uint32_t map_table_length;
 
329
  grub_uint32_t num_part_maps;
 
330
  struct grub_udf_regid imp_ident;
 
331
  grub_uint8_t imp_use[128];
 
332
  struct grub_udf_extent_ad integrity_seq_ext;
 
333
  grub_uint8_t part_maps[1608];
 
334
} __attribute__ ((packed));
 
335
 
 
336
struct grub_udf_aed
 
337
{
 
338
  struct grub_udf_tag tag;
 
339
  grub_uint32_t prev_ae;
 
340
  grub_uint32_t ae_len;
 
341
} __attribute__ ((packed));
 
342
 
 
343
struct grub_udf_data
 
344
{
 
345
  grub_disk_t disk;
 
346
  struct grub_udf_lvd lvd;
 
347
  struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
 
348
  struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
 
349
  struct grub_udf_long_ad root_icb;
 
350
  int npd, npm, lbshift;
 
351
};
 
352
 
 
353
struct grub_fshelp_node
 
354
{
 
355
  struct grub_udf_data *data;
 
356
  union
 
357
  {
 
358
    struct grub_udf_file_entry fe;
 
359
    struct grub_udf_extended_file_entry efe;
 
360
  };
 
361
  int part_ref;
 
362
};
 
363
 
 
364
static grub_dl_t my_mod;
 
365
 
 
366
static grub_uint32_t
 
367
grub_udf_get_block (struct grub_udf_data *data,
 
368
                    grub_uint16_t part_ref, grub_uint32_t block)
 
369
{
 
370
  part_ref = U16 (part_ref);
 
371
 
 
372
  if (part_ref >= data->npm)
 
373
    {
 
374
      grub_error (GRUB_ERR_BAD_FS, "invalid part ref");
 
375
      return 0;
 
376
    }
 
377
 
 
378
  return (U32 (data->pds[data->pms[part_ref]->type1.part_num].start)
 
379
          + U32 (block));
 
380
}
 
381
 
 
382
static grub_err_t
 
383
grub_udf_read_icb (struct grub_udf_data *data,
 
384
                   struct grub_udf_long_ad *icb,
 
385
                   struct grub_fshelp_node *node)
 
386
{
 
387
  grub_uint32_t block;
 
388
 
 
389
  block = grub_udf_get_block (data,
 
390
                              icb->block.part_ref,
 
391
                              icb->block.block_num);
 
392
 
 
393
  if (grub_errno)
 
394
    return grub_errno;
 
395
 
 
396
  if (grub_disk_read (data->disk, block << data->lbshift, 0,
 
397
                      sizeof (struct grub_udf_file_entry),
 
398
                      &node->fe))
 
399
    return grub_errno;
 
400
 
 
401
  if ((U16 (node->fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FE) &&
 
402
      (U16 (node->fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_EFE))
 
403
    return grub_error (GRUB_ERR_BAD_FS, "invalid fe/efe descriptor");
 
404
 
 
405
  node->part_ref = icb->block.part_ref;
 
406
  node->data = data;
 
407
  return 0;
 
408
}
 
409
 
 
410
static grub_disk_addr_t
 
411
grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
 
412
{
 
413
  char *buf = NULL;
 
414
  char *ptr;
 
415
  grub_ssize_t len;
 
416
  grub_disk_addr_t filebytes;
 
417
 
 
418
  switch (U16 (node->fe.tag.tag_ident))
 
419
    {
 
420
    case GRUB_UDF_TAG_IDENT_FE:
 
421
      ptr = (char *) &node->fe.ext_attr[0] + U32 (node->fe.ext_attr_length);
 
422
      len = U32 (node->fe.alloc_descs_length);
 
423
      break;
 
424
 
 
425
    case GRUB_UDF_TAG_IDENT_EFE:
 
426
      ptr = (char *) &node->efe.ext_attr[0] + U32 (node->efe.ext_attr_length);
 
427
      len = U32 (node->efe.alloc_descs_length);
 
428
      break;
 
429
 
 
430
    default:
 
431
      grub_error (GRUB_ERR_BAD_FS, "invalid file entry");
 
432
      return 0;
 
433
    }
 
434
 
 
435
  if ((U16 (node->fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK)
 
436
      == GRUB_UDF_ICBTAG_FLAG_AD_SHORT)
 
437
    {
 
438
      struct grub_udf_short_ad *ad = (struct grub_udf_short_ad *) ptr;
 
439
 
 
440
      filebytes = fileblock * U32 (node->data->lvd.bsize);
 
441
      while (len >= (grub_ssize_t) sizeof (struct grub_udf_short_ad))
 
442
        {
 
443
          grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff;
 
444
          grub_uint32_t adtype = U32 (ad->length) >> 30;
 
445
          if (adtype == 3)
 
446
            {
 
447
              struct grub_udf_aed *extension;
 
448
              grub_disk_addr_t sec = grub_udf_get_block(node->data,
 
449
                                                        node->part_ref,
 
450
                                                        ad->position);
 
451
              if (!buf)
 
452
                {
 
453
                  buf = grub_malloc (U32 (node->data->lvd.bsize));
 
454
                  if (!buf)
 
455
                    return 0;
 
456
                }
 
457
              if (grub_disk_read (node->data->disk, sec << node->data->lbshift,
 
458
                                  0, adlen, buf))
 
459
                goto fail;
 
460
 
 
461
              extension = (struct grub_udf_aed *) buf;
 
462
              if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED)
 
463
                {
 
464
                  grub_error (GRUB_ERR_BAD_FS, "invalid aed tag");
 
465
                  goto fail;
 
466
                }
 
467
 
 
468
              len = U32 (extension->ae_len);
 
469
              ad = (struct grub_udf_short_ad *)
 
470
                    (buf + sizeof (struct grub_udf_aed));
 
471
              continue;
 
472
            }
 
473
 
 
474
          if (filebytes < adlen)
 
475
            {
 
476
              grub_uint32_t ad_pos = ad->position;
 
477
              grub_free (buf);
 
478
              return ((U32 (ad_pos) & GRUB_UDF_EXT_MASK) ? 0 :
 
479
                      (grub_udf_get_block (node->data, node->part_ref, ad_pos)
 
480
                       + (filebytes >> (GRUB_DISK_SECTOR_BITS
 
481
                                        + node->data->lbshift))));
 
482
            }
 
483
 
 
484
          filebytes -= adlen;
 
485
          ad++;
 
486
          len -= sizeof (struct grub_udf_short_ad);
 
487
        }
 
488
    }
 
489
  else
 
490
    {
 
491
      struct grub_udf_long_ad *ad = (struct grub_udf_long_ad *) ptr;
 
492
 
 
493
      filebytes = fileblock * U32 (node->data->lvd.bsize);
 
494
      while (len >= (grub_ssize_t) sizeof (struct grub_udf_long_ad))
 
495
        {
 
496
          grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff;
 
497
          grub_uint32_t adtype = U32 (ad->length) >> 30;
 
498
          if (adtype == 3)
 
499
            {
 
500
              struct grub_udf_aed *extension;
 
501
              grub_disk_addr_t sec = grub_udf_get_block(node->data,
 
502
                                                        ad->block.part_ref,
 
503
                                                        ad->block.block_num);
 
504
              if (!buf)
 
505
                {
 
506
                  buf = grub_malloc (U32 (node->data->lvd.bsize));
 
507
                  if (!buf)
 
508
                    return 0;
 
509
                }
 
510
              if (grub_disk_read (node->data->disk, sec << node->data->lbshift,
 
511
                                  0, adlen, buf))
 
512
                goto fail;
 
513
 
 
514
              extension = (struct grub_udf_aed *) buf;
 
515
              if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED)
 
516
                {
 
517
                  grub_error (GRUB_ERR_BAD_FS, "invalid aed tag");
 
518
                  goto fail;
 
519
                }
 
520
 
 
521
              len = U32 (extension->ae_len);
 
522
              ad = (struct grub_udf_long_ad *)
 
523
                    (buf + sizeof (struct grub_udf_aed));
 
524
              continue;
 
525
            }
 
526
              
 
527
          if (filebytes < adlen)
 
528
            {
 
529
              grub_uint32_t ad_block_num = ad->block.block_num;
 
530
              grub_uint32_t ad_part_ref = ad->block.part_ref;
 
531
              grub_free (buf);
 
532
              return ((U32 (ad_block_num) & GRUB_UDF_EXT_MASK) ?  0 :
 
533
                      (grub_udf_get_block (node->data, ad_part_ref,
 
534
                                           ad_block_num)
 
535
                       + (filebytes >> (GRUB_DISK_SECTOR_BITS
 
536
                                        + node->data->lbshift))));
 
537
            }
 
538
 
 
539
          filebytes -= adlen;
 
540
          ad++;
 
541
          len -= sizeof (struct grub_udf_long_ad);
 
542
        }
 
543
    }
 
544
 
 
545
fail:
 
546
  if (buf)
 
547
    grub_free (buf);
 
548
 
 
549
  return 0;
 
550
}
 
551
 
 
552
static grub_ssize_t
 
553
grub_udf_read_file (grub_fshelp_node_t node,
 
554
                    void NESTED_FUNC_ATTR
 
555
                    (*read_hook) (grub_disk_addr_t sector,
 
556
                                  unsigned offset, unsigned length),
 
557
                    grub_off_t pos, grub_size_t len, char *buf)
 
558
{
 
559
  switch (U16 (node->fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK)
 
560
    {
 
561
    case GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB:
 
562
      {
 
563
        char *ptr;
 
564
 
 
565
        ptr = ((U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) ?
 
566
               ((char *) &node->fe.ext_attr[0]
 
567
                + U32 (node->fe.ext_attr_length)) :
 
568
               ((char *) &node->efe.ext_attr[0]
 
569
                + U32 (node->efe.ext_attr_length)));
 
570
 
 
571
        grub_memcpy (buf, ptr + pos, len);
 
572
 
 
573
        return len;
 
574
      }
 
575
 
 
576
    case GRUB_UDF_ICBTAG_FLAG_AD_EXT:
 
577
      grub_error (GRUB_ERR_BAD_FS, "invalid extent type");
 
578
      return 0;
 
579
    }
 
580
 
 
581
  return  grub_fshelp_read_file (node->data->disk, node, read_hook,
 
582
                                 pos, len, buf, grub_udf_read_block,
 
583
                                 U64 (node->fe.file_size),
 
584
                                 node->data->lbshift);
 
585
}
 
586
 
 
587
static unsigned sblocklist[] = { 256, 512, 0 };
 
588
 
 
589
static struct grub_udf_data *
 
590
grub_udf_mount (grub_disk_t disk)
 
591
{
 
592
  struct grub_udf_data *data = 0;
 
593
  struct grub_udf_fileset root_fs;
 
594
  unsigned *sblklist;
 
595
  grub_uint32_t block, vblock;
 
596
  int i, lbshift;
 
597
 
 
598
  data = grub_malloc (sizeof (struct grub_udf_data));
 
599
  if (!data)
 
600
    return 0;
 
601
 
 
602
  data->disk = disk;
 
603
 
 
604
  /* Search for Anchor Volume Descriptor Pointer (AVDP)
 
605
   * and determine logical block size.  */
 
606
  block = 0;
 
607
  for (lbshift = 0; lbshift < 4; lbshift++)
 
608
    {
 
609
      for (sblklist = sblocklist; *sblklist; sblklist++)
 
610
        {
 
611
          struct grub_udf_avdp avdp;
 
612
 
 
613
          if (grub_disk_read (disk, *sblklist << lbshift, 0,
 
614
                              sizeof (struct grub_udf_avdp), &avdp))
 
615
            {
 
616
              grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
617
              goto fail;
 
618
            }
 
619
 
 
620
          if (U16 (avdp.tag.tag_ident) == GRUB_UDF_TAG_IDENT_AVDP &&
 
621
              U32 (avdp.tag.tag_location) == *sblklist)
 
622
            {
 
623
              block = U32 (avdp.vds.start);
 
624
              break;
 
625
            }
 
626
        }
 
627
 
 
628
      if (block)
 
629
        break;
 
630
    }
 
631
 
 
632
  if (!block)
 
633
    {
 
634
      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
635
      goto fail;
 
636
    }
 
637
  data->lbshift = lbshift;
 
638
 
 
639
  /* Search for Volume Recognition Sequence (VRS).  */
 
640
  for (vblock = (32767 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1;;
 
641
       vblock += (2047 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1)
 
642
    {
 
643
      struct grub_udf_vrs vrs;
 
644
 
 
645
      if (grub_disk_read (disk, vblock << lbshift, 0,
 
646
                          sizeof (struct grub_udf_vrs), &vrs))
 
647
        {
 
648
          grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
649
          goto fail;
 
650
        }
 
651
 
 
652
      if ((!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR03, 5)) ||
 
653
          (!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR02, 5)))
 
654
        break;
 
655
 
 
656
      if ((grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BEA01, 5)) &&
 
657
          (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BOOT2, 5)) &&
 
658
          (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CD001, 5)) &&
 
659
          (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CDW02, 5)) &&
 
660
          (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_TEA01, 5)))
 
661
        {
 
662
          grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
663
          goto fail;
 
664
        }
 
665
    }
 
666
 
 
667
  data->npd = data->npm = 0;
 
668
  /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD).  */
 
669
  while (1)
 
670
    {
 
671
      struct grub_udf_tag tag;
 
672
 
 
673
      if (grub_disk_read (disk, block << lbshift, 0,
 
674
                          sizeof (struct grub_udf_tag), &tag))
 
675
        {
 
676
          grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
677
          goto fail;
 
678
        }
 
679
 
 
680
      tag.tag_ident = U16 (tag.tag_ident);
 
681
      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
 
682
        {
 
683
          if (data->npd >= GRUB_UDF_MAX_PDS)
 
684
            {
 
685
              grub_error (GRUB_ERR_BAD_FS, "too many PDs");
 
686
              goto fail;
 
687
            }
 
688
 
 
689
          if (grub_disk_read (disk, block << lbshift, 0,
 
690
                              sizeof (struct grub_udf_pd),
 
691
                              &data->pds[data->npd]))
 
692
            {
 
693
              grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
694
              goto fail;
 
695
            }
 
696
 
 
697
          data->npd++;
 
698
        }
 
699
      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_LVD)
 
700
        {
 
701
          int k;
 
702
 
 
703
          struct grub_udf_partmap *ppm;
 
704
 
 
705
          if (grub_disk_read (disk, block << lbshift, 0,
 
706
                              sizeof (struct grub_udf_lvd),
 
707
                              &data->lvd))
 
708
            {
 
709
              grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
710
              goto fail;
 
711
            }
 
712
 
 
713
          if (data->npm + U32 (data->lvd.num_part_maps) > GRUB_UDF_MAX_PMS)
 
714
            {
 
715
              grub_error (GRUB_ERR_BAD_FS, "too many partition maps");
 
716
              goto fail;
 
717
            }
 
718
 
 
719
          ppm = (struct grub_udf_partmap *) &data->lvd.part_maps;
 
720
          for (k = U32 (data->lvd.num_part_maps); k > 0; k--)
 
721
            {
 
722
              if (ppm->type != GRUB_UDF_PARTMAP_TYPE_1)
 
723
                {
 
724
                  grub_error (GRUB_ERR_BAD_FS, "partmap type not supported");
 
725
                  goto fail;
 
726
                }
 
727
 
 
728
              data->pms[data->npm++] = ppm;
 
729
              ppm = (struct grub_udf_partmap *) ((char *) ppm +
 
730
                                                 U32 (ppm->length));
 
731
            }
 
732
        }
 
733
      else if (tag.tag_ident > GRUB_UDF_TAG_IDENT_TD)
 
734
        {
 
735
          grub_error (GRUB_ERR_BAD_FS, "invalid tag ident");
 
736
          goto fail;
 
737
        }
 
738
      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_TD)
 
739
        break;
 
740
 
 
741
      block++;
 
742
    }
 
743
 
 
744
  for (i = 0; i < data->npm; i++)
 
745
    {
 
746
      int j;
 
747
 
 
748
      for (j = 0; j < data->npd; j++)
 
749
        if (data->pms[i]->type1.part_num == data->pds[j].part_num)
 
750
          {
 
751
            data->pms[i]->type1.part_num = j;
 
752
            break;
 
753
          }
 
754
 
 
755
      if (j == data->npd)
 
756
        {
 
757
          grub_error (GRUB_ERR_BAD_FS, "can\'t find PD");
 
758
          goto fail;
 
759
        }
 
760
    }
 
761
 
 
762
  block = grub_udf_get_block (data,
 
763
                              data->lvd.root_fileset.block.part_ref,
 
764
                              data->lvd.root_fileset.block.block_num);
 
765
 
 
766
  if (grub_errno)
 
767
    goto fail;
 
768
 
 
769
  if (grub_disk_read (disk, block << lbshift, 0,
 
770
                      sizeof (struct grub_udf_fileset), &root_fs))
 
771
    {
 
772
      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
 
773
      goto fail;
 
774
    }
 
775
 
 
776
  if (U16 (root_fs.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FSD)
 
777
    {
 
778
      grub_error (GRUB_ERR_BAD_FS, "invalid fileset descriptor");
 
779
      goto fail;
 
780
    }
 
781
 
 
782
  data->root_icb = root_fs.root_icb;
 
783
 
 
784
  return data;
 
785
 
 
786
fail:
 
787
  grub_free (data);
 
788
  return 0;
 
789
}
 
790
 
 
791
static int
 
792
grub_udf_iterate_dir (grub_fshelp_node_t dir,
 
793
                      int NESTED_FUNC_ATTR
 
794
                      (*hook) (const char *filename,
 
795
                               enum grub_fshelp_filetype filetype,
 
796
                               grub_fshelp_node_t node))
 
797
{
 
798
  grub_fshelp_node_t child;
 
799
  struct grub_udf_file_ident dirent;
 
800
  grub_off_t offset = 0;
 
801
 
 
802
  child = grub_malloc (sizeof (struct grub_fshelp_node));
 
803
  if (!child)
 
804
    return 0;
 
805
 
 
806
  /* The current directory is not stored.  */
 
807
  grub_memcpy ((char *) child, (char *) dir,
 
808
               sizeof (struct grub_fshelp_node));
 
809
 
 
810
  if (hook (".", GRUB_FSHELP_DIR, child))
 
811
    return 1;
 
812
 
 
813
  while (offset < U64 (dir->fe.file_size))
 
814
    {
 
815
      if (grub_udf_read_file (dir, 0, offset, sizeof (dirent),
 
816
                              (char *) &dirent) != sizeof (dirent))
 
817
        return 0;
 
818
 
 
819
      if (U16 (dirent.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FID)
 
820
        {
 
821
          grub_error (GRUB_ERR_BAD_FS, "invalid fid tag");
 
822
          return 0;
 
823
        }
 
824
 
 
825
      offset += sizeof (dirent) + U16 (dirent.imp_use_length);
 
826
      if (!(dirent.characteristics & GRUB_UDF_FID_CHAR_DELETED))
 
827
        {
 
828
          child = grub_malloc (sizeof (struct grub_fshelp_node));
 
829
          if (!child)
 
830
            return 0;
 
831
 
 
832
          if (grub_udf_read_icb (dir->data, &dirent.icb, child))
 
833
            return 0;
 
834
 
 
835
          if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT)
 
836
            {
 
837
              /* This is the parent directory.  */
 
838
              if (hook ("..", GRUB_FSHELP_DIR, child))
 
839
                return 1;
 
840
            }
 
841
          else
 
842
            {
 
843
              enum grub_fshelp_filetype type;
 
844
              grub_uint8_t raw[dirent.file_ident_length];
 
845
              grub_uint16_t utf16[dirent.file_ident_length - 1];
 
846
              grub_uint8_t filename[dirent.file_ident_length * 2];
 
847
              grub_size_t utf16len = 0;
 
848
 
 
849
              type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ?
 
850
                      (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG));
 
851
 
 
852
              if ((grub_udf_read_file (dir, 0, offset,
 
853
                                       dirent.file_ident_length,
 
854
                                       (char *) raw))
 
855
                  != dirent.file_ident_length)
 
856
                return 0;
 
857
 
 
858
              if (raw[0] == 8)
 
859
                {
 
860
                  unsigned i;
 
861
                  utf16len = dirent.file_ident_length - 1;
 
862
                  for (i = 0; i < utf16len; i++)
 
863
                    utf16[i] = raw[i + 1];
 
864
                }
 
865
              if (raw[0] == 16)
 
866
                {
 
867
                  unsigned i;
 
868
                  utf16len = (dirent.file_ident_length - 1) / 2;
 
869
                  for (i = 0; i < utf16len; i++)
 
870
                    utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2];
 
871
                }
 
872
              if (raw[0] == 8 || raw[0] == 16)
 
873
                {
 
874
                  *grub_utf16_to_utf8 (filename, utf16, utf16len) = '\0';
 
875
 
 
876
                  if (hook ((char *) filename, type, child))
 
877
                    return 1;
 
878
                }
 
879
            }
 
880
        }
 
881
 
 
882
      /* Align to dword boundary.  */
 
883
      offset = (offset + dirent.file_ident_length + 3) & (~3);
 
884
    }
 
885
 
 
886
  return 0;
 
887
}
 
888
 
 
889
static grub_err_t
 
890
grub_udf_dir (grub_device_t device, const char *path,
 
891
              int (*hook) (const char *filename,
 
892
                           const struct grub_dirhook_info *info))
 
893
{
 
894
  struct grub_udf_data *data = 0;
 
895
  struct grub_fshelp_node rootnode;
 
896
  struct grub_fshelp_node *foundnode;
 
897
 
 
898
  auto int NESTED_FUNC_ATTR iterate (const char *filename,
 
899
                                     enum grub_fshelp_filetype filetype,
 
900
                                     grub_fshelp_node_t node);
 
901
 
 
902
  int NESTED_FUNC_ATTR iterate (const char *filename,
 
903
                                enum grub_fshelp_filetype filetype,
 
904
                                grub_fshelp_node_t node)
 
905
  {
 
906
      struct grub_dirhook_info info;
 
907
      grub_memset (&info, 0, sizeof (info));
 
908
      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
 
909
      grub_free (node);
 
910
      return hook (filename, &info);
 
911
  }
 
912
 
 
913
  grub_dl_ref (my_mod);
 
914
 
 
915
  data = grub_udf_mount (device->disk);
 
916
  if (!data)
 
917
    goto fail;
 
918
 
 
919
  if (grub_udf_read_icb (data, &data->root_icb, &rootnode))
 
920
    goto fail;
 
921
 
 
922
  if (grub_fshelp_find_file (path, &rootnode,
 
923
                             &foundnode,
 
924
                             grub_udf_iterate_dir, 0, GRUB_FSHELP_DIR))
 
925
    goto fail;
 
926
 
 
927
  grub_udf_iterate_dir (foundnode, iterate);
 
928
 
 
929
  if (foundnode != &rootnode)
 
930
    grub_free (foundnode);
 
931
 
 
932
fail:
 
933
  grub_free (data);
 
934
 
 
935
  grub_dl_unref (my_mod);
 
936
 
 
937
  return grub_errno;
 
938
}
 
939
 
 
940
static grub_err_t
 
941
grub_udf_open (struct grub_file *file, const char *name)
 
942
{
 
943
  struct grub_udf_data *data;
 
944
  struct grub_fshelp_node rootnode;
 
945
  struct grub_fshelp_node *foundnode;
 
946
 
 
947
  grub_dl_ref (my_mod);
 
948
 
 
949
  data = grub_udf_mount (file->device->disk);
 
950
  if (!data)
 
951
    goto fail;
 
952
 
 
953
  if (grub_udf_read_icb (data, &data->root_icb, &rootnode))
 
954
    goto fail;
 
955
 
 
956
  if (grub_fshelp_find_file (name, &rootnode,
 
957
                             &foundnode,
 
958
                             grub_udf_iterate_dir, 0, GRUB_FSHELP_REG))
 
959
    goto fail;
 
960
 
 
961
  file->data = foundnode;
 
962
  file->offset = 0;
 
963
  file->size = U64 (foundnode->fe.file_size);
 
964
 
 
965
  return 0;
 
966
 
 
967
fail:
 
968
  grub_dl_unref (my_mod);
 
969
 
 
970
  grub_free (data);
 
971
 
 
972
  return grub_errno;
 
973
}
 
974
 
 
975
static grub_ssize_t
 
976
grub_udf_read (grub_file_t file, char *buf, grub_size_t len)
 
977
{
 
978
  struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data;
 
979
 
 
980
  return grub_udf_read_file (node, file->read_hook, file->offset, len, buf);
 
981
}
 
982
 
 
983
static grub_err_t
 
984
grub_udf_close (grub_file_t file)
 
985
{
 
986
  if (file->data)
 
987
    {
 
988
      struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data;
 
989
 
 
990
      grub_free (node->data);
 
991
      grub_free (node);
 
992
    }
 
993
 
 
994
  grub_dl_unref (my_mod);
 
995
 
 
996
  return GRUB_ERR_NONE;
 
997
}
 
998
 
 
999
static grub_err_t
 
1000
grub_udf_label (grub_device_t device, char **label)
 
1001
{
 
1002
  struct grub_udf_data *data;
 
1003
  data = grub_udf_mount (device->disk);
 
1004
 
 
1005
  if (data)
 
1006
    {
 
1007
      *label = grub_strdup ((char *) &data->lvd.ident[1]);
 
1008
      grub_free (data);
 
1009
    }
 
1010
  else
 
1011
    *label = 0;
 
1012
 
 
1013
  return grub_errno;
 
1014
}
 
1015
 
 
1016
static struct grub_fs grub_udf_fs = {
 
1017
  .name = "udf",
 
1018
  .dir = grub_udf_dir,
 
1019
  .open = grub_udf_open,
 
1020
  .read = grub_udf_read,
 
1021
  .close = grub_udf_close,
 
1022
  .label = grub_udf_label,
 
1023
  .next = 0
 
1024
};
 
1025
 
 
1026
GRUB_MOD_INIT (udf)
 
1027
{
 
1028
  grub_fs_register (&grub_udf_fs);
 
1029
  my_mod = mod;
 
1030
}
 
1031
 
 
1032
GRUB_MOD_FINI (udf)
 
1033
{
 
1034
  grub_fs_unregister (&grub_udf_fs);
 
1035
}