]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c
keep up with 1.0.67 (#1464)
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / fs / udf.c
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 #include <grub/datetime.h>
30 #include <grub/udf.h>
31 #include <grub/ventoy.h>
32
33 GRUB_MOD_LICENSE ("GPLv3+");
34
35 #define OFFSET_OF(TYPE, MEMBER) ((grub_size_t) &((TYPE *)0)->MEMBER)
36
37 grub_uint32_t g_last_disk_read_sector = 0;
38 grub_uint32_t g_last_fe_tag_ident = 0;
39 grub_uint32_t g_last_icb_read_sector = 0;
40 grub_uint32_t g_last_icb_read_sector_tag_ident = 0;
41 grub_uint32_t g_last_fileattr_read_sector = 0;
42 grub_uint32_t g_last_fileattr_read_sector_tag_ident = 0;
43 grub_uint32_t g_last_fileattr_offset = 0;
44 grub_uint64_t g_last_pd_length_offset = 0;
45
46 #define GRUB_UDF_MAX_PDS 2
47 #define GRUB_UDF_MAX_PMS 6
48
49 #define U16 grub_le_to_cpu16
50 #define U32 grub_le_to_cpu32
51 #define U64 grub_le_to_cpu64
52
53 #define GRUB_UDF_TAG_IDENT_PVD 0x0001
54 #define GRUB_UDF_TAG_IDENT_AVDP 0x0002
55 #define GRUB_UDF_TAG_IDENT_VDP 0x0003
56 #define GRUB_UDF_TAG_IDENT_IUVD 0x0004
57 #define GRUB_UDF_TAG_IDENT_PD 0x0005
58 #define GRUB_UDF_TAG_IDENT_LVD 0x0006
59 #define GRUB_UDF_TAG_IDENT_USD 0x0007
60 #define GRUB_UDF_TAG_IDENT_TD 0x0008
61 #define GRUB_UDF_TAG_IDENT_LVID 0x0009
62
63 #define GRUB_UDF_TAG_IDENT_FSD 0x0100
64 #define GRUB_UDF_TAG_IDENT_FID 0x0101
65 #define GRUB_UDF_TAG_IDENT_AED 0x0102
66 #define GRUB_UDF_TAG_IDENT_IE 0x0103
67 #define GRUB_UDF_TAG_IDENT_TE 0x0104
68 #define GRUB_UDF_TAG_IDENT_FE 0x0105
69 #define GRUB_UDF_TAG_IDENT_EAHD 0x0106
70 #define GRUB_UDF_TAG_IDENT_USE 0x0107
71 #define GRUB_UDF_TAG_IDENT_SBD 0x0108
72 #define GRUB_UDF_TAG_IDENT_PIE 0x0109
73 #define GRUB_UDF_TAG_IDENT_EFE 0x010A
74
75 #define GRUB_UDF_ICBTAG_TYPE_UNDEF 0x00
76 #define GRUB_UDF_ICBTAG_TYPE_USE 0x01
77 #define GRUB_UDF_ICBTAG_TYPE_PIE 0x02
78 #define GRUB_UDF_ICBTAG_TYPE_IE 0x03
79 #define GRUB_UDF_ICBTAG_TYPE_DIRECTORY 0x04
80 #define GRUB_UDF_ICBTAG_TYPE_REGULAR 0x05
81 #define GRUB_UDF_ICBTAG_TYPE_BLOCK 0x06
82 #define GRUB_UDF_ICBTAG_TYPE_CHAR 0x07
83 #define GRUB_UDF_ICBTAG_TYPE_EA 0x08
84 #define GRUB_UDF_ICBTAG_TYPE_FIFO 0x09
85 #define GRUB_UDF_ICBTAG_TYPE_SOCKET 0x0A
86 #define GRUB_UDF_ICBTAG_TYPE_TE 0x0B
87 #define GRUB_UDF_ICBTAG_TYPE_SYMLINK 0x0C
88 #define GRUB_UDF_ICBTAG_TYPE_STREAMDIR 0x0D
89
90 #define GRUB_UDF_ICBTAG_FLAG_AD_MASK 0x0007
91 #define GRUB_UDF_ICBTAG_FLAG_AD_SHORT 0x0000
92 #define GRUB_UDF_ICBTAG_FLAG_AD_LONG 0x0001
93 #define GRUB_UDF_ICBTAG_FLAG_AD_EXT 0x0002
94 #define GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB 0x0003
95
96 #define GRUB_UDF_EXT_NORMAL 0x00000000
97 #define GRUB_UDF_EXT_NREC_ALLOC 0x40000000
98 #define GRUB_UDF_EXT_NREC_NALLOC 0x80000000
99 #define GRUB_UDF_EXT_MASK 0xC0000000
100
101 #define GRUB_UDF_FID_CHAR_HIDDEN 0x01
102 #define GRUB_UDF_FID_CHAR_DIRECTORY 0x02
103 #define GRUB_UDF_FID_CHAR_DELETED 0x04
104 #define GRUB_UDF_FID_CHAR_PARENT 0x08
105 #define GRUB_UDF_FID_CHAR_METADATA 0x10
106
107 #define GRUB_UDF_STD_IDENT_BEA01 "BEA01"
108 #define GRUB_UDF_STD_IDENT_BOOT2 "BOOT2"
109 #define GRUB_UDF_STD_IDENT_CD001 "CD001"
110 #define GRUB_UDF_STD_IDENT_CDW02 "CDW02"
111 #define GRUB_UDF_STD_IDENT_NSR02 "NSR02"
112 #define GRUB_UDF_STD_IDENT_NSR03 "NSR03"
113 #define GRUB_UDF_STD_IDENT_TEA01 "TEA01"
114
115 #define GRUB_UDF_CHARSPEC_TYPE_CS0 0x00
116 #define GRUB_UDF_CHARSPEC_TYPE_CS1 0x01
117 #define GRUB_UDF_CHARSPEC_TYPE_CS2 0x02
118 #define GRUB_UDF_CHARSPEC_TYPE_CS3 0x03
119 #define GRUB_UDF_CHARSPEC_TYPE_CS4 0x04
120 #define GRUB_UDF_CHARSPEC_TYPE_CS5 0x05
121 #define GRUB_UDF_CHARSPEC_TYPE_CS6 0x06
122 #define GRUB_UDF_CHARSPEC_TYPE_CS7 0x07
123 #define GRUB_UDF_CHARSPEC_TYPE_CS8 0x08
124
125 #define GRUB_UDF_PARTMAP_TYPE_1 1
126 #define GRUB_UDF_PARTMAP_TYPE_2 2
127
128 struct grub_udf_lb_addr
129 {
130 grub_uint32_t block_num;
131 grub_uint16_t part_ref;
132 } GRUB_PACKED;
133
134 struct grub_udf_short_ad
135 {
136 grub_uint32_t length;
137 grub_uint32_t position;
138 } GRUB_PACKED;
139
140 struct grub_udf_long_ad
141 {
142 grub_uint32_t length;
143 struct grub_udf_lb_addr block;
144 grub_uint8_t imp_use[6];
145 } GRUB_PACKED;
146
147 struct grub_udf_extent_ad
148 {
149 grub_uint32_t length;
150 grub_uint32_t start;
151 } GRUB_PACKED;
152
153 struct grub_udf_charspec
154 {
155 grub_uint8_t charset_type;
156 grub_uint8_t charset_info[63];
157 } GRUB_PACKED;
158
159 struct grub_udf_timestamp
160 {
161 grub_uint16_t type_and_timezone;
162 grub_uint16_t year;
163 grub_uint8_t month;
164 grub_uint8_t day;
165 grub_uint8_t hour;
166 grub_uint8_t minute;
167 grub_uint8_t second;
168 grub_uint8_t centi_seconds;
169 grub_uint8_t hundreds_of_micro_seconds;
170 grub_uint8_t micro_seconds;
171 } GRUB_PACKED;
172
173 struct grub_udf_regid
174 {
175 grub_uint8_t flags;
176 grub_uint8_t ident[23];
177 grub_uint8_t ident_suffix[8];
178 } GRUB_PACKED;
179
180 struct grub_udf_tag
181 {
182 grub_uint16_t tag_ident;
183 grub_uint16_t desc_version;
184 grub_uint8_t tag_checksum;
185 grub_uint8_t reserved;
186 grub_uint16_t tag_serial_number;
187 grub_uint16_t desc_crc;
188 grub_uint16_t desc_crc_length;
189 grub_uint32_t tag_location;
190 } GRUB_PACKED;
191
192 struct grub_udf_fileset
193 {
194 struct grub_udf_tag tag;
195 struct grub_udf_timestamp datetime;
196 grub_uint16_t interchange_level;
197 grub_uint16_t max_interchange_level;
198 grub_uint32_t charset_list;
199 grub_uint32_t max_charset_list;
200 grub_uint32_t fileset_num;
201 grub_uint32_t fileset_desc_num;
202 struct grub_udf_charspec vol_charset;
203 grub_uint8_t vol_ident[128];
204 struct grub_udf_charspec fileset_charset;
205 grub_uint8_t fileset_ident[32];
206 grub_uint8_t copyright_file_ident[32];
207 grub_uint8_t abstract_file_ident[32];
208 struct grub_udf_long_ad root_icb;
209 struct grub_udf_regid domain_ident;
210 struct grub_udf_long_ad next_ext;
211 struct grub_udf_long_ad streamdir_icb;
212 } GRUB_PACKED;
213
214 struct grub_udf_icbtag
215 {
216 grub_uint32_t prior_recorded_num_direct_entries;
217 grub_uint16_t strategy_type;
218 grub_uint16_t strategy_parameter;
219 grub_uint16_t num_entries;
220 grub_uint8_t reserved;
221 grub_uint8_t file_type;
222 struct grub_udf_lb_addr parent_idb;
223 grub_uint16_t flags;
224 } GRUB_PACKED;
225
226 struct grub_udf_file_ident
227 {
228 struct grub_udf_tag tag;
229 grub_uint16_t version_num;
230 grub_uint8_t characteristics;
231 #define MAX_FILE_IDENT_LENGTH 256
232 grub_uint8_t file_ident_length;
233 struct grub_udf_long_ad icb;
234 grub_uint16_t imp_use_length;
235 } GRUB_PACKED;
236
237 struct grub_udf_file_entry
238 {
239 struct grub_udf_tag tag;
240 struct grub_udf_icbtag icbtag;
241 grub_uint32_t uid;
242 grub_uint32_t gid;
243 grub_uint32_t permissions;
244 grub_uint16_t link_count;
245 grub_uint8_t record_format;
246 grub_uint8_t record_display_attr;
247 grub_uint32_t record_length;
248 grub_uint64_t file_size;
249 grub_uint64_t blocks_recorded;
250 struct grub_udf_timestamp access_time;
251 struct grub_udf_timestamp modification_time;
252 struct grub_udf_timestamp attr_time;
253 grub_uint32_t checkpoint;
254 struct grub_udf_long_ad extended_attr_idb;
255 struct grub_udf_regid imp_ident;
256 grub_uint64_t unique_id;
257 grub_uint32_t ext_attr_length;
258 grub_uint32_t alloc_descs_length;
259 grub_uint8_t ext_attr[0];
260 } GRUB_PACKED;
261
262 struct grub_udf_extended_file_entry
263 {
264 struct grub_udf_tag tag;
265 struct grub_udf_icbtag icbtag;
266 grub_uint32_t uid;
267 grub_uint32_t gid;
268 grub_uint32_t permissions;
269 grub_uint16_t link_count;
270 grub_uint8_t record_format;
271 grub_uint8_t record_display_attr;
272 grub_uint32_t record_length;
273 grub_uint64_t file_size;
274 grub_uint64_t object_size;
275 grub_uint64_t blocks_recorded;
276 struct grub_udf_timestamp access_time;
277 struct grub_udf_timestamp modification_time;
278 struct grub_udf_timestamp create_time;
279 struct grub_udf_timestamp attr_time;
280 grub_uint32_t checkpoint;
281 grub_uint32_t reserved;
282 struct grub_udf_long_ad extended_attr_icb;
283 struct grub_udf_long_ad streamdir_icb;
284 struct grub_udf_regid imp_ident;
285 grub_uint64_t unique_id;
286 grub_uint32_t ext_attr_length;
287 grub_uint32_t alloc_descs_length;
288 grub_uint8_t ext_attr[0];
289 } GRUB_PACKED;
290
291 struct grub_udf_vrs
292 {
293 grub_uint8_t type;
294 grub_uint8_t magic[5];
295 grub_uint8_t version;
296 } GRUB_PACKED;
297
298 struct grub_udf_avdp
299 {
300 struct grub_udf_tag tag;
301 struct grub_udf_extent_ad vds;
302 } GRUB_PACKED;
303
304 struct grub_udf_pd
305 {
306 struct grub_udf_tag tag;
307 grub_uint32_t seq_num;
308 grub_uint16_t flags;
309 grub_uint16_t part_num;
310 struct grub_udf_regid contents;
311 grub_uint8_t contents_use[128];
312 grub_uint32_t access_type;
313 grub_uint32_t start;
314 grub_uint32_t length;
315 } GRUB_PACKED;
316
317 struct grub_udf_partmap
318 {
319 grub_uint8_t type;
320 grub_uint8_t length;
321 union
322 {
323 struct
324 {
325 grub_uint16_t seq_num;
326 grub_uint16_t part_num;
327 } type1;
328
329 struct
330 {
331 grub_uint8_t ident[62];
332 } type2;
333 };
334 } GRUB_PACKED;
335
336 struct grub_udf_pvd
337 {
338 struct grub_udf_tag tag;
339 grub_uint32_t seq_num;
340 grub_uint32_t pvd_num;
341 grub_uint8_t ident[32];
342 grub_uint16_t vol_seq_num;
343 grub_uint16_t max_vol_seq_num;
344 grub_uint16_t interchange_level;
345 grub_uint16_t max_interchange_level;
346 grub_uint32_t charset_list;
347 grub_uint32_t max_charset_list;
348 grub_uint8_t volset_ident[128];
349 struct grub_udf_charspec desc_charset;
350 struct grub_udf_charspec expl_charset;
351 struct grub_udf_extent_ad vol_abstract;
352 struct grub_udf_extent_ad vol_copyright;
353 struct grub_udf_regid app_ident;
354 struct grub_udf_timestamp recording_time;
355 struct grub_udf_regid imp_ident;
356 grub_uint8_t imp_use[64];
357 grub_uint32_t pred_vds_loc;
358 grub_uint16_t flags;
359 grub_uint8_t reserved[22];
360 } GRUB_PACKED;
361
362 struct grub_udf_lvd
363 {
364 struct grub_udf_tag tag;
365 grub_uint32_t seq_num;
366 struct grub_udf_charspec charset;
367 grub_uint8_t ident[128];
368 grub_uint32_t bsize;
369 struct grub_udf_regid domain_ident;
370 struct grub_udf_long_ad root_fileset;
371 grub_uint32_t map_table_length;
372 grub_uint32_t num_part_maps;
373 struct grub_udf_regid imp_ident;
374 grub_uint8_t imp_use[128];
375 struct grub_udf_extent_ad integrity_seq_ext;
376 grub_uint8_t part_maps[1608];
377 } GRUB_PACKED;
378
379 struct grub_udf_aed
380 {
381 struct grub_udf_tag tag;
382 grub_uint32_t prev_ae;
383 grub_uint32_t ae_len;
384 } GRUB_PACKED;
385
386 struct grub_udf_data
387 {
388 grub_disk_t disk;
389 struct grub_udf_pvd pvd;
390 struct grub_udf_lvd lvd;
391 struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
392 struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
393 struct grub_udf_long_ad root_icb;
394 int npd, npm, lbshift;
395 };
396
397 struct grub_fshelp_node
398 {
399 struct grub_udf_data *data;
400 int part_ref;
401 union
402 {
403 struct grub_udf_file_entry fe;
404 struct grub_udf_extended_file_entry efe;
405 char raw[0];
406 } block;
407 };
408
409 static inline grub_size_t
410 get_fshelp_size (struct grub_udf_data *data)
411 {
412 struct grub_fshelp_node *x = NULL;
413 return sizeof (*x)
414 + (1 << (GRUB_DISK_SECTOR_BITS
415 + data->lbshift)) - sizeof (x->block);
416 }
417
418 static grub_dl_t my_mod;
419
420 static grub_uint32_t
421 grub_udf_get_block (struct grub_udf_data *data,
422 grub_uint16_t part_ref, grub_uint32_t block)
423 {
424 part_ref = U16 (part_ref);
425
426 if (part_ref >= data->npm)
427 {
428 grub_error (GRUB_ERR_BAD_FS, "invalid part ref");
429 return 0;
430 }
431
432 return (U32 (data->pds[data->pms[part_ref]->type1.part_num].start)
433 + U32 (block));
434 }
435
436 static grub_err_t
437 grub_udf_read_icb (struct grub_udf_data *data,
438 struct grub_udf_long_ad *icb,
439 struct grub_fshelp_node *node)
440 {
441 grub_uint32_t block;
442
443 block = grub_udf_get_block (data,
444 icb->block.part_ref,
445 icb->block.block_num);
446
447 if (grub_errno)
448 return grub_errno;
449
450 if (grub_disk_read (data->disk, block << data->lbshift, 0,
451 1 << (GRUB_DISK_SECTOR_BITS
452 + data->lbshift),
453 &node->block))
454 return grub_errno;
455
456 g_last_disk_read_sector = block;
457 g_last_fe_tag_ident = U16(node->block.fe.tag.tag_ident);
458
459 if ((U16 (node->block.fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FE) &&
460 (U16 (node->block.fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_EFE))
461 return grub_error (GRUB_ERR_BAD_FS, "invalid fe/efe descriptor");
462
463 node->part_ref = icb->block.part_ref;
464 node->data = data;
465 return 0;
466 }
467
468 static grub_disk_addr_t
469 grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
470 {
471 char *buf = NULL;
472 char *ptr;
473 grub_ssize_t len;
474 grub_disk_addr_t filebytes;
475
476 switch (U16 (node->block.fe.tag.tag_ident))
477 {
478 case GRUB_UDF_TAG_IDENT_FE:
479 ptr = (char *) &node->block.fe.ext_attr[0] + U32 (node->block.fe.ext_attr_length);
480 len = U32 (node->block.fe.alloc_descs_length);
481 break;
482
483 case GRUB_UDF_TAG_IDENT_EFE:
484 ptr = (char *) &node->block.efe.ext_attr[0] + U32 (node->block.efe.ext_attr_length);
485 len = U32 (node->block.efe.alloc_descs_length);
486 break;
487
488 default:
489 grub_error (GRUB_ERR_BAD_FS, "invalid file entry");
490 return 0;
491 }
492
493 if ((U16 (node->block.fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK)
494 == GRUB_UDF_ICBTAG_FLAG_AD_SHORT)
495 {
496 struct grub_udf_short_ad *ad = (struct grub_udf_short_ad *) ptr;
497
498 filebytes = fileblock * U32 (node->data->lvd.bsize);
499 while (len >= (grub_ssize_t) sizeof (struct grub_udf_short_ad))
500 {
501 grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff;
502 grub_uint32_t adtype = U32 (ad->length) >> 30;
503 if (adtype == 3)
504 {
505 struct grub_udf_aed *extension;
506 grub_disk_addr_t sec = grub_udf_get_block(node->data,
507 node->part_ref,
508 ad->position);
509 if (!buf)
510 {
511 buf = grub_malloc (U32 (node->data->lvd.bsize));
512 if (!buf)
513 return 0;
514 }
515 if (grub_disk_read (node->data->disk, sec << node->data->lbshift,
516 0, adlen, buf))
517 goto fail;
518
519 extension = (struct grub_udf_aed *) buf;
520 if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED)
521 {
522 grub_error (GRUB_ERR_BAD_FS, "invalid aed tag");
523 goto fail;
524 }
525
526 len = U32 (extension->ae_len);
527 ad = (struct grub_udf_short_ad *)
528 (buf + sizeof (struct grub_udf_aed));
529 continue;
530 }
531
532 if (filebytes < adlen)
533 {
534 grub_uint32_t ad_pos = ad->position;
535 grub_free (buf);
536 return ((U32 (ad_pos) & GRUB_UDF_EXT_MASK) ? 0 :
537 (grub_udf_get_block (node->data, node->part_ref, ad_pos)
538 + (filebytes >> (GRUB_DISK_SECTOR_BITS
539 + node->data->lbshift))));
540 }
541
542 filebytes -= adlen;
543 ad++;
544 len -= sizeof (struct grub_udf_short_ad);
545 }
546 }
547 else
548 {
549 struct grub_udf_long_ad *ad = (struct grub_udf_long_ad *) ptr;
550
551 filebytes = fileblock * U32 (node->data->lvd.bsize);
552 while (len >= (grub_ssize_t) sizeof (struct grub_udf_long_ad))
553 {
554 grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff;
555 grub_uint32_t adtype = U32 (ad->length) >> 30;
556 if (adtype == 3)
557 {
558 struct grub_udf_aed *extension;
559 grub_disk_addr_t sec = grub_udf_get_block(node->data,
560 ad->block.part_ref,
561 ad->block.block_num);
562 if (!buf)
563 {
564 buf = grub_malloc (U32 (node->data->lvd.bsize));
565 if (!buf)
566 return 0;
567 }
568 if (grub_disk_read (node->data->disk, sec << node->data->lbshift,
569 0, adlen, buf))
570 goto fail;
571
572 extension = (struct grub_udf_aed *) buf;
573 if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED)
574 {
575 grub_error (GRUB_ERR_BAD_FS, "invalid aed tag");
576 goto fail;
577 }
578
579 len = U32 (extension->ae_len);
580 ad = (struct grub_udf_long_ad *)
581 (buf + sizeof (struct grub_udf_aed));
582 continue;
583 }
584
585 if (filebytes < adlen)
586 {
587 grub_uint32_t ad_block_num = ad->block.block_num;
588 grub_uint32_t ad_part_ref = ad->block.part_ref;
589 grub_free (buf);
590 return ((U32 (ad_block_num) & GRUB_UDF_EXT_MASK) ? 0 :
591 (grub_udf_get_block (node->data, ad_part_ref,
592 ad_block_num)
593 + (filebytes >> (GRUB_DISK_SECTOR_BITS
594 + node->data->lbshift))));
595 }
596
597 filebytes -= adlen;
598 ad++;
599 len -= sizeof (struct grub_udf_long_ad);
600 }
601 }
602
603 fail:
604 grub_free (buf);
605
606 return 0;
607 }
608
609 static grub_ssize_t
610 grub_udf_read_file (grub_fshelp_node_t node,
611 grub_disk_read_hook_t read_hook, void *read_hook_data,
612 grub_off_t pos, grub_size_t len, char *buf)
613 {
614 switch (U16 (node->block.fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK)
615 {
616 case GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB:
617 {
618 char *ptr;
619
620 ptr = ((U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) ?
621 ((char *) &node->block.fe.ext_attr[0]
622 + U32 (node->block.fe.ext_attr_length)) :
623 ((char *) &node->block.efe.ext_attr[0]
624 + U32 (node->block.efe.ext_attr_length)));
625
626 grub_memcpy (buf, ptr + pos, len);
627
628 return len;
629 }
630
631 case GRUB_UDF_ICBTAG_FLAG_AD_EXT:
632 grub_error (GRUB_ERR_BAD_FS, "invalid extent type");
633 return 0;
634 }
635
636 return grub_fshelp_read_file (node->data->disk, node,
637 read_hook, read_hook_data,
638 pos, len, buf, grub_udf_read_block,
639 U64 (node->block.fe.file_size),
640 node->data->lbshift, 0);
641 }
642
643 static unsigned sblocklist[] = { 256, 512, 0 };
644
645 static struct grub_udf_data *
646 grub_udf_mount (grub_disk_t disk)
647 {
648 struct grub_udf_data *data = 0;
649 struct grub_udf_fileset root_fs;
650 unsigned *sblklist;
651 grub_uint32_t block, vblock;
652 int i, lbshift;
653
654 data = grub_malloc (sizeof (struct grub_udf_data));
655 if (!data)
656 return 0;
657
658 data->disk = disk;
659
660 /* Search for Anchor Volume Descriptor Pointer (AVDP)
661 * and determine logical block size. */
662 block = 0;
663 for (lbshift = 0; lbshift < 4; lbshift++)
664 {
665 for (sblklist = sblocklist; *sblklist; sblklist++)
666 {
667 struct grub_udf_avdp avdp;
668
669 if (grub_disk_read (disk, *sblklist << lbshift, 0,
670 sizeof (struct grub_udf_avdp), &avdp))
671 {
672 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
673 goto fail;
674 }
675
676 if (U16 (avdp.tag.tag_ident) == GRUB_UDF_TAG_IDENT_AVDP &&
677 U32 (avdp.tag.tag_location) == *sblklist)
678 {
679 block = U32 (avdp.vds.start);
680 break;
681 }
682 }
683
684 if (block)
685 break;
686 }
687
688 if (!block)
689 {
690 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
691 goto fail;
692 }
693 data->lbshift = lbshift;
694
695 /* Search for Volume Recognition Sequence (VRS). */
696 for (vblock = (32767 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1;;
697 vblock += (2047 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1)
698 {
699 struct grub_udf_vrs vrs;
700
701 if (grub_disk_read (disk, vblock << lbshift, 0,
702 sizeof (struct grub_udf_vrs), &vrs))
703 {
704 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
705 goto fail;
706 }
707
708 if ((!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR03, 5)) ||
709 (!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR02, 5)))
710 break;
711
712 if ((grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BEA01, 5)) &&
713 (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BOOT2, 5)) &&
714 (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CD001, 5)) &&
715 (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CDW02, 5)) &&
716 (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_TEA01, 5)))
717 {
718 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
719 goto fail;
720 }
721 }
722
723 data->npd = data->npm = 0;
724 /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD). */
725 while (1)
726 {
727 struct grub_udf_tag tag;
728
729 if (grub_disk_read (disk, block << lbshift, 0,
730 sizeof (struct grub_udf_tag), &tag))
731 {
732 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
733 goto fail;
734 }
735
736 tag.tag_ident = U16 (tag.tag_ident);
737 if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
738 {
739 if (grub_disk_read (disk, block << lbshift, 0,
740 sizeof (struct grub_udf_pvd),
741 &data->pvd))
742 {
743 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
744 goto fail;
745 }
746 }
747 else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
748 {
749 if (data->npd >= GRUB_UDF_MAX_PDS)
750 {
751 grub_error (GRUB_ERR_BAD_FS, "too many PDs");
752 goto fail;
753 }
754
755 if (grub_disk_read (disk, block << lbshift, 0,
756 sizeof (struct grub_udf_pd),
757 &data->pds[data->npd]))
758 {
759 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
760 goto fail;
761 }
762
763 g_last_pd_length_offset = (block << lbshift) * 512 + OFFSET_OF(struct grub_udf_pd, length);
764
765 data->npd++;
766 }
767 else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_LVD)
768 {
769 int k;
770
771 struct grub_udf_partmap *ppm;
772
773 if (grub_disk_read (disk, block << lbshift, 0,
774 sizeof (struct grub_udf_lvd),
775 &data->lvd))
776 {
777 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
778 goto fail;
779 }
780
781 if (data->npm + U32 (data->lvd.num_part_maps) > GRUB_UDF_MAX_PMS)
782 {
783 grub_error (GRUB_ERR_BAD_FS, "too many partition maps");
784 goto fail;
785 }
786
787 ppm = (struct grub_udf_partmap *) &data->lvd.part_maps;
788 for (k = U32 (data->lvd.num_part_maps); k > 0; k--)
789 {
790 if (ppm->type != GRUB_UDF_PARTMAP_TYPE_1)
791 {
792 grub_error (GRUB_ERR_BAD_FS, "partmap type not supported");
793 goto fail;
794 }
795
796 data->pms[data->npm++] = ppm;
797 ppm = (struct grub_udf_partmap *) ((char *) ppm +
798 U32 (ppm->length));
799 }
800 }
801 else if (tag.tag_ident > GRUB_UDF_TAG_IDENT_TD)
802 {
803 grub_error (GRUB_ERR_BAD_FS, "invalid tag ident");
804 goto fail;
805 }
806 else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_TD)
807 break;
808
809 block++;
810 }
811
812 for (i = 0; i < data->npm; i++)
813 {
814 int j;
815
816 for (j = 0; j < data->npd; j++)
817 if (data->pms[i]->type1.part_num == data->pds[j].part_num)
818 {
819 data->pms[i]->type1.part_num = j;
820 break;
821 }
822
823 if (j == data->npd)
824 {
825 grub_error (GRUB_ERR_BAD_FS, "can\'t find PD");
826 goto fail;
827 }
828 }
829
830 block = grub_udf_get_block (data,
831 data->lvd.root_fileset.block.part_ref,
832 data->lvd.root_fileset.block.block_num);
833
834 if (grub_errno)
835 goto fail;
836
837 if (grub_disk_read (disk, block << lbshift, 0,
838 sizeof (struct grub_udf_fileset), &root_fs))
839 {
840 grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
841 goto fail;
842 }
843
844 if (U16 (root_fs.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FSD)
845 {
846 grub_error (GRUB_ERR_BAD_FS, "invalid fileset descriptor");
847 goto fail;
848 }
849
850 data->root_icb = root_fs.root_icb;
851
852 return data;
853
854 fail:
855 grub_free (data);
856 return 0;
857 }
858
859 #ifdef GRUB_UTIL
860 grub_disk_addr_t
861 grub_udf_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
862 {
863 grub_disk_addr_t ret;
864 static struct grub_udf_data *data;
865
866 data = grub_udf_mount (disk);
867 if (!data)
868 return 0;
869
870 ret = U32 (data->pds[data->pms[0]->type1.part_num].start);
871 *sec_per_lcn = 1ULL << data->lbshift;
872 grub_free (data);
873 return ret;
874 }
875 #endif
876
877 static char *
878 read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
879 {
880 grub_uint16_t *utf16 = NULL;
881 grub_size_t utf16len = 0;
882
883 if (sz == 0)
884 return NULL;
885
886 if (raw[0] != 8 && raw[0] != 16)
887 return NULL;
888
889 if (raw[0] == 8)
890 {
891 unsigned i;
892 utf16len = sz - 1;
893 utf16 = grub_malloc (utf16len * sizeof (utf16[0]));
894 if (!utf16)
895 return NULL;
896 for (i = 0; i < utf16len; i++)
897 utf16[i] = raw[i + 1];
898 }
899 if (raw[0] == 16)
900 {
901 unsigned i;
902 utf16len = (sz - 1) / 2;
903 utf16 = grub_malloc (utf16len * sizeof (utf16[0]));
904 if (!utf16)
905 return NULL;
906 for (i = 0; i < utf16len; i++)
907 utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2];
908 }
909 if (!outbuf)
910 outbuf = grub_malloc (utf16len * GRUB_MAX_UTF8_PER_UTF16 + 1);
911 if (outbuf)
912 *grub_utf16_to_utf8 ((grub_uint8_t *) outbuf, utf16, utf16len) = '\0';
913 grub_free (utf16);
914 return outbuf;
915 }
916
917 static char *
918 read_dstring (const grub_uint8_t *raw, grub_size_t sz)
919 {
920 grub_size_t len;
921
922 if (raw[0] == 0) {
923 char *outbuf = grub_malloc (1);
924 if (!outbuf)
925 return NULL;
926 outbuf[0] = 0;
927 return outbuf;
928 }
929
930 len = raw[sz - 1];
931 if (len > sz - 1)
932 len = sz - 1;
933 return read_string (raw, len, NULL);
934 }
935
936 static int
937 grub_udf_iterate_dir (grub_fshelp_node_t dir,
938 grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
939 {
940 grub_fshelp_node_t child;
941 struct grub_udf_file_ident dirent;
942 grub_off_t offset = 0;
943
944 child = grub_malloc (get_fshelp_size (dir->data));
945 if (!child)
946 return 0;
947
948 /* The current directory is not stored. */
949 grub_memcpy (child, dir, get_fshelp_size (dir->data));
950
951 if (hook (".", GRUB_FSHELP_DIR, child, hook_data))
952 return 1;
953
954 while (offset < U64 (dir->block.fe.file_size))
955 {
956 if (grub_udf_read_file (dir, 0, 0, offset, sizeof (dirent),
957 (char *) &dirent) != sizeof (dirent))
958 return 0;
959
960 if (U16 (dirent.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FID)
961 {
962 grub_error (GRUB_ERR_BAD_FS, "invalid fid tag");
963 return 0;
964 }
965
966 offset += sizeof (dirent) + U16 (dirent.imp_use_length);
967 if (!(dirent.characteristics & GRUB_UDF_FID_CHAR_DELETED))
968 {
969 child = grub_malloc (get_fshelp_size (dir->data));
970 if (!child)
971 return 0;
972
973 if (grub_udf_read_icb (dir->data, &dirent.icb, child))
974 return 0;
975
976 g_last_icb_read_sector = g_last_disk_read_sector;
977 g_last_icb_read_sector_tag_ident = g_last_fe_tag_ident;
978 if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT)
979 {
980 /* This is the parent directory. */
981 if (hook ("..", GRUB_FSHELP_DIR, child, hook_data))
982 return 1;
983 }
984 else
985 {
986 enum grub_fshelp_filetype type;
987 char *filename;
988 grub_uint8_t raw[MAX_FILE_IDENT_LENGTH];
989
990 type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ?
991 (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG));
992 if (child->block.fe.icbtag.file_type == GRUB_UDF_ICBTAG_TYPE_SYMLINK)
993 type = GRUB_FSHELP_SYMLINK;
994
995 if ((grub_udf_read_file (dir, 0, 0, offset,
996 dirent.file_ident_length,
997 (char *) raw))
998 != dirent.file_ident_length)
999 return 0;
1000
1001 filename = read_string (raw, dirent.file_ident_length, 0);
1002 if (!filename)
1003 grub_print_error ();
1004
1005 if (filename && hook (filename, type, child, hook_data))
1006 {
1007 g_last_fileattr_read_sector = g_last_icb_read_sector;
1008 g_last_fileattr_read_sector_tag_ident = g_last_icb_read_sector_tag_ident;
1009 g_last_fileattr_offset = (grub_uint32_t)((child->block.fe.ext_attr + child->block.fe.ext_attr_length) - (grub_uint8_t *)&(child->block.fe));
1010 grub_free (filename);
1011 return 1;
1012 }
1013 grub_free (filename);
1014 }
1015 }
1016
1017 /* Align to dword boundary. */
1018 offset = (offset + dirent.file_ident_length + 3) & (~3);
1019 }
1020
1021 return 0;
1022 }
1023
1024 static char *
1025 grub_udf_read_symlink (grub_fshelp_node_t node)
1026 {
1027 grub_size_t sz = U64 (node->block.fe.file_size);
1028 grub_uint8_t *raw;
1029 const grub_uint8_t *ptr;
1030 char *out, *optr;
1031
1032 if (sz < 4)
1033 return NULL;
1034 raw = grub_malloc (sz);
1035 if (!raw)
1036 return NULL;
1037 if (grub_udf_read_file (node, NULL, NULL, 0, sz, (char *) raw) < 0)
1038 {
1039 grub_free (raw);
1040 return NULL;
1041 }
1042
1043 out = grub_malloc (sz * 2 + 1);
1044 if (!out)
1045 {
1046 grub_free (raw);
1047 return NULL;
1048 }
1049
1050 optr = out;
1051
1052 for (ptr = raw; ptr < raw + sz; )
1053 {
1054 grub_size_t s;
1055 if ((grub_size_t) (ptr - raw + 4) > sz)
1056 goto fail;
1057 if (!(ptr[2] == 0 && ptr[3] == 0))
1058 goto fail;
1059 s = 4 + ptr[1];
1060 if ((grub_size_t) (ptr - raw + s) > sz)
1061 goto fail;
1062 switch (*ptr)
1063 {
1064 case 1:
1065 if (ptr[1])
1066 goto fail;
1067 /* Fallthrough. */
1068 case 2:
1069 /* in 4 bytes. out: 1 byte. */
1070 optr = out;
1071 *optr++ = '/';
1072 break;
1073 case 3:
1074 /* in 4 bytes. out: 3 bytes. */
1075 if (optr != out)
1076 *optr++ = '/';
1077 *optr++ = '.';
1078 *optr++ = '.';
1079 break;
1080 case 4:
1081 /* in 4 bytes. out: 2 bytes. */
1082 if (optr != out)
1083 *optr++ = '/';
1084 *optr++ = '.';
1085 break;
1086 case 5:
1087 /* in 4 + n bytes. out, at most: 1 + 2 * n bytes. */
1088 if (optr != out)
1089 *optr++ = '/';
1090 if (!read_string (ptr + 4, s - 4, optr))
1091 goto fail;
1092 optr += grub_strlen (optr);
1093 break;
1094 default:
1095 goto fail;
1096 }
1097 ptr += s;
1098 }
1099 *optr = 0;
1100 grub_free (raw);
1101 return out;
1102
1103 fail:
1104 grub_free (raw);
1105 grub_free (out);
1106 grub_error (GRUB_ERR_BAD_FS, "invalid symlink");
1107 return NULL;
1108 }
1109
1110 /* Context for grub_udf_dir. */
1111 struct grub_udf_dir_ctx
1112 {
1113 grub_fs_dir_hook_t hook;
1114 void *hook_data;
1115 };
1116
1117 /* Helper for grub_udf_dir. */
1118 static int
1119 grub_udf_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
1120 grub_fshelp_node_t node, void *data)
1121 {
1122 struct grub_udf_dir_ctx *ctx = data;
1123 struct grub_dirhook_info info;
1124 const struct grub_udf_timestamp *tstamp = NULL;
1125
1126 grub_memset (&info, 0, sizeof (info));
1127 info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
1128 if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE)
1129 tstamp = &node->block.fe.modification_time;
1130 else if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE)
1131 tstamp = &node->block.efe.modification_time;
1132
1133 if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000)
1134 {
1135 grub_int16_t tz;
1136 struct grub_datetime datetime;
1137
1138 datetime.year = U16 (tstamp->year);
1139 datetime.month = tstamp->month;
1140 datetime.day = tstamp->day;
1141 datetime.hour = tstamp->hour;
1142 datetime.minute = tstamp->minute;
1143 datetime.second = tstamp->second;
1144
1145 tz = U16 (tstamp->type_and_timezone) & 0xfff;
1146 if (tz & 0x800)
1147 tz |= 0xf000;
1148 if (tz == -2047)
1149 tz = 0;
1150
1151 info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime);
1152
1153 info.mtime -= 60 * tz;
1154 }
1155 if (!info.dir)
1156 info.size = U64 (node->block.fe.file_size);
1157 grub_free (node);
1158 return ctx->hook (filename, &info, ctx->hook_data);
1159 }
1160
1161 static grub_err_t
1162 grub_udf_dir (grub_device_t device, const char *path,
1163 grub_fs_dir_hook_t hook, void *hook_data)
1164 {
1165 struct grub_udf_dir_ctx ctx = { hook, hook_data };
1166 struct grub_udf_data *data = 0;
1167 struct grub_fshelp_node *rootnode = 0;
1168 struct grub_fshelp_node *foundnode = 0;
1169
1170 grub_dl_ref (my_mod);
1171
1172 data = grub_udf_mount (device->disk);
1173 if (!data)
1174 goto fail;
1175
1176 rootnode = grub_malloc (get_fshelp_size (data));
1177 if (!rootnode)
1178 goto fail;
1179
1180 if (grub_udf_read_icb (data, &data->root_icb, rootnode))
1181 goto fail;
1182
1183 if (grub_fshelp_find_file (path, rootnode,
1184 &foundnode,
1185 grub_udf_iterate_dir, grub_udf_read_symlink,
1186 GRUB_FSHELP_DIR))
1187 goto fail;
1188
1189 grub_udf_iterate_dir (foundnode, grub_udf_dir_iter, &ctx);
1190
1191 if (foundnode != rootnode)
1192 grub_free (foundnode);
1193
1194 fail:
1195 grub_free (rootnode);
1196
1197 grub_free (data);
1198
1199 grub_dl_unref (my_mod);
1200
1201 return grub_errno;
1202 }
1203
1204 static grub_err_t
1205 grub_udf_open (struct grub_file *file, const char *name)
1206 {
1207 struct grub_udf_data *data;
1208 struct grub_fshelp_node *rootnode = 0;
1209 struct grub_fshelp_node *foundnode;
1210
1211 grub_dl_ref (my_mod);
1212
1213 data = grub_udf_mount (file->device->disk);
1214 if (!data)
1215 goto fail;
1216
1217 rootnode = grub_malloc (get_fshelp_size (data));
1218 if (!rootnode)
1219 goto fail;
1220
1221 if (grub_udf_read_icb (data, &data->root_icb, rootnode))
1222 goto fail;
1223
1224 if (grub_fshelp_find_file (name, rootnode,
1225 &foundnode,
1226 grub_udf_iterate_dir, grub_udf_read_symlink,
1227 GRUB_FSHELP_REG))
1228 goto fail;
1229
1230 file->data = foundnode;
1231 file->offset = 0;
1232 file->size = U64 (foundnode->block.fe.file_size);
1233
1234 grub_free (rootnode);
1235
1236 return 0;
1237
1238 fail:
1239 grub_dl_unref (my_mod);
1240
1241 grub_free (data);
1242 grub_free (rootnode);
1243
1244 return grub_errno;
1245 }
1246
1247 static grub_ssize_t
1248 grub_udf_read (grub_file_t file, char *buf, grub_size_t len)
1249 {
1250 struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data;
1251
1252 return grub_udf_read_file (node, file->read_hook, file->read_hook_data,
1253 file->offset, len, buf);
1254 }
1255
1256 static grub_err_t
1257 grub_udf_close (grub_file_t file)
1258 {
1259 if (file->data)
1260 {
1261 struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data;
1262
1263 grub_free (node->data);
1264 grub_free (node);
1265 }
1266
1267 grub_dl_unref (my_mod);
1268
1269 return GRUB_ERR_NONE;
1270 }
1271
1272 static grub_err_t
1273 grub_udf_label (grub_device_t device, char **label)
1274 {
1275 struct grub_udf_data *data;
1276 data = grub_udf_mount (device->disk);
1277
1278 if (data)
1279 {
1280 *label = read_dstring (data->lvd.ident, sizeof (data->lvd.ident));
1281 grub_free (data);
1282 }
1283 else
1284 *label = 0;
1285
1286 return grub_errno;
1287 }
1288
1289 static char *
1290 gen_uuid_from_volset (char *volset_ident)
1291 {
1292 grub_size_t i;
1293 grub_size_t len;
1294 grub_size_t nonhexpos;
1295 grub_uint8_t buf[17];
1296 char *uuid;
1297
1298 len = grub_strlen (volset_ident);
1299 if (len < 8)
1300 return NULL;
1301
1302 uuid = grub_malloc (17);
1303 if (!uuid)
1304 return NULL;
1305
1306 if (len > 16)
1307 len = 16;
1308
1309 grub_memset (buf, 0, sizeof (buf));
1310 grub_memcpy (buf, volset_ident, len);
1311
1312 nonhexpos = 16;
1313 for (i = 0; i < 16; ++i)
1314 {
1315 if (!grub_isxdigit (buf[i]))
1316 {
1317 nonhexpos = i;
1318 break;
1319 }
1320 }
1321
1322 if (nonhexpos < 8)
1323 {
1324 grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
1325 buf[0], buf[1], buf[2], buf[3],
1326 buf[4], buf[5], buf[6], buf[7]);
1327 }
1328 else if (nonhexpos < 16)
1329 {
1330 for (i = 0; i < 8; ++i)
1331 uuid[i] = grub_tolower (buf[i]);
1332 grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
1333 buf[8], buf[9], buf[10], buf[11]);
1334 }
1335 else
1336 {
1337 for (i = 0; i < 16; ++i)
1338 uuid[i] = grub_tolower (buf[i]);
1339 uuid[16] = 0;
1340 }
1341
1342 return uuid;
1343 }
1344
1345 static grub_err_t
1346 grub_udf_uuid (grub_device_t device, char **uuid)
1347 {
1348 char *volset_ident;
1349 struct grub_udf_data *data;
1350 data = grub_udf_mount (device->disk);
1351
1352 if (data)
1353 {
1354 volset_ident = read_dstring (data->pvd.volset_ident, sizeof (data->pvd.volset_ident));
1355 if (volset_ident)
1356 {
1357 *uuid = gen_uuid_from_volset (volset_ident);
1358 grub_free (volset_ident);
1359 }
1360 else
1361 *uuid = 0;
1362 grub_free (data);
1363 }
1364 else
1365 *uuid = 0;
1366
1367 return grub_errno;
1368 }
1369
1370 grub_uint64_t grub_udf_get_file_offset(grub_file_t file)
1371 {
1372 grub_disk_addr_t sector;
1373 struct grub_fshelp_node *node = (struct grub_fshelp_node *)file->data;
1374
1375 sector = grub_udf_read_block(node, 0);
1376
1377 return 512 * (sector << node->data->lbshift);
1378 }
1379
1380 grub_uint64_t grub_udf_get_last_pd_size_offset(void)
1381 {
1382 return g_last_pd_length_offset;
1383 }
1384
1385 grub_uint64_t grub_udf_get_last_file_attr_offset
1386 (
1387 grub_file_t file,
1388 grub_uint32_t *startBlock,
1389 grub_uint64_t *fe_entry_size_offset
1390 )
1391 {
1392 grub_uint64_t attr_offset;
1393 struct grub_fshelp_node *node;
1394 struct grub_udf_data *data;
1395
1396 node = (struct grub_fshelp_node *)file->data;
1397 data = node->data;
1398
1399 *startBlock = data->pds[data->pms[0]->type1.part_num].start;
1400
1401 attr_offset = g_last_fileattr_read_sector * 2048 + g_last_fileattr_offset;
1402
1403 if (GRUB_UDF_TAG_IDENT_FE == g_last_fileattr_read_sector_tag_ident)
1404 {
1405 *fe_entry_size_offset = g_last_fileattr_read_sector * 2048 + OFFSET_OF(struct grub_udf_file_entry, file_size);
1406 }
1407 else
1408 {
1409 *fe_entry_size_offset = g_last_fileattr_read_sector * 2048 + OFFSET_OF(struct grub_udf_extended_file_entry, file_size);
1410 }
1411
1412 return attr_offset;
1413 }
1414
1415 static struct grub_fs grub_udf_fs = {
1416 .name = "udf",
1417 .fs_dir = grub_udf_dir,
1418 .fs_open = grub_udf_open,
1419 .fs_read = grub_udf_read,
1420 .fs_close = grub_udf_close,
1421 .fs_label = grub_udf_label,
1422 .fs_uuid = grub_udf_uuid,
1423 #ifdef GRUB_UTIL
1424 .reserved_first_sector = 1,
1425 .blocklist_install = 1,
1426 #endif
1427 .next = 0
1428 };
1429
1430 GRUB_MOD_INIT (udf)
1431 {
1432 grub_fs_register (&grub_udf_fs);
1433 my_mod = mod;
1434 }
1435
1436 GRUB_MOD_FINI (udf)
1437 {
1438 grub_fs_unregister (&grub_udf_fs);
1439 }