1 /* udf.c - Universal Disk Format filesystem. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/file.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
26 #include <grub/types.h>
27 #include <grub/fshelp.h>
28 #include <grub/charset.h>
29 #include <grub/datetime.h>
31 #include <grub/ventoy.h>
33 GRUB_MOD_LICENSE ("GPLv3+");
35 #define OFFSET_OF(TYPE, MEMBER) ((grub_size_t) &((TYPE *)0)->MEMBER)
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;
46 #define GRUB_UDF_MAX_PDS 2
47 #define GRUB_UDF_MAX_PMS 6
49 #define U16 grub_le_to_cpu16
50 #define U32 grub_le_to_cpu32
51 #define U64 grub_le_to_cpu64
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
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
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
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
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
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
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"
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
125 #define GRUB_UDF_PARTMAP_TYPE_1 1
126 #define GRUB_UDF_PARTMAP_TYPE_2 2
128 struct grub_udf_lb_addr
130 grub_uint32_t block_num
;
131 grub_uint16_t part_ref
;
134 struct grub_udf_short_ad
136 grub_uint32_t length
;
137 grub_uint32_t position
;
140 struct grub_udf_long_ad
142 grub_uint32_t length
;
143 struct grub_udf_lb_addr block
;
144 grub_uint8_t imp_use
[6];
147 struct grub_udf_extent_ad
149 grub_uint32_t length
;
153 struct grub_udf_charspec
155 grub_uint8_t charset_type
;
156 grub_uint8_t charset_info
[63];
159 struct grub_udf_timestamp
161 grub_uint16_t type_and_timezone
;
168 grub_uint8_t centi_seconds
;
169 grub_uint8_t hundreds_of_micro_seconds
;
170 grub_uint8_t micro_seconds
;
173 struct grub_udf_regid
176 grub_uint8_t ident
[23];
177 grub_uint8_t ident_suffix
[8];
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
;
192 struct grub_udf_fileset
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
;
214 struct grub_udf_icbtag
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
;
226 struct grub_udf_file_ident
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
;
237 struct grub_udf_file_entry
239 struct grub_udf_tag tag
;
240 struct grub_udf_icbtag icbtag
;
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];
262 struct grub_udf_extended_file_entry
264 struct grub_udf_tag tag
;
265 struct grub_udf_icbtag icbtag
;
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];
294 grub_uint8_t magic
[5];
295 grub_uint8_t version
;
300 struct grub_udf_tag tag
;
301 struct grub_udf_extent_ad vds
;
306 struct grub_udf_tag tag
;
307 grub_uint32_t seq_num
;
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
;
314 grub_uint32_t length
;
317 struct grub_udf_partmap
325 grub_uint16_t seq_num
;
326 grub_uint16_t part_num
;
331 grub_uint8_t ident
[62];
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
;
359 grub_uint8_t reserved
[22];
364 struct grub_udf_tag tag
;
365 grub_uint32_t seq_num
;
366 struct grub_udf_charspec charset
;
367 grub_uint8_t ident
[128];
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];
381 struct grub_udf_tag tag
;
382 grub_uint32_t prev_ae
;
383 grub_uint32_t ae_len
;
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
;
397 struct grub_fshelp_node
399 struct grub_udf_data
*data
;
403 struct grub_udf_file_entry fe
;
404 struct grub_udf_extended_file_entry efe
;
409 static inline grub_size_t
410 get_fshelp_size (struct grub_udf_data
*data
)
412 struct grub_fshelp_node
*x
= NULL
;
414 + (1 << (GRUB_DISK_SECTOR_BITS
415 + data
->lbshift
)) - sizeof (x
->block
);
418 static grub_dl_t my_mod
;
421 grub_udf_get_block (struct grub_udf_data
*data
,
422 grub_uint16_t part_ref
, grub_uint32_t block
)
424 part_ref
= U16 (part_ref
);
426 if (part_ref
>= data
->npm
)
428 grub_error (GRUB_ERR_BAD_FS
, "invalid part ref");
432 return (U32 (data
->pds
[data
->pms
[part_ref
]->type1
.part_num
].start
)
437 grub_udf_read_icb (struct grub_udf_data
*data
,
438 struct grub_udf_long_ad
*icb
,
439 struct grub_fshelp_node
*node
)
443 block
= grub_udf_get_block (data
,
445 icb
->block
.block_num
);
450 if (grub_disk_read (data
->disk
, block
<< data
->lbshift
, 0,
451 1 << (GRUB_DISK_SECTOR_BITS
456 g_last_disk_read_sector
= block
;
457 g_last_fe_tag_ident
= U16(node
->block
.fe
.tag
.tag_ident
);
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");
463 node
->part_ref
= icb
->block
.part_ref
;
468 static grub_disk_addr_t
469 grub_udf_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
474 grub_disk_addr_t filebytes
;
476 switch (U16 (node
->block
.fe
.tag
.tag_ident
))
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
);
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
);
489 grub_error (GRUB_ERR_BAD_FS
, "invalid file entry");
493 if ((U16 (node
->block
.fe
.icbtag
.flags
) & GRUB_UDF_ICBTAG_FLAG_AD_MASK
)
494 == GRUB_UDF_ICBTAG_FLAG_AD_SHORT
)
496 struct grub_udf_short_ad
*ad
= (struct grub_udf_short_ad
*) ptr
;
498 filebytes
= fileblock
* U32 (node
->data
->lvd
.bsize
);
499 while (len
>= (grub_ssize_t
) sizeof (struct grub_udf_short_ad
))
501 grub_uint32_t adlen
= U32 (ad
->length
) & 0x3fffffff;
502 grub_uint32_t adtype
= U32 (ad
->length
) >> 30;
505 struct grub_udf_aed
*extension
;
506 grub_disk_addr_t sec
= grub_udf_get_block(node
->data
,
511 buf
= grub_malloc (U32 (node
->data
->lvd
.bsize
));
515 if (grub_disk_read (node
->data
->disk
, sec
<< node
->data
->lbshift
,
519 extension
= (struct grub_udf_aed
*) buf
;
520 if (U16 (extension
->tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_AED
)
522 grub_error (GRUB_ERR_BAD_FS
, "invalid aed tag");
526 len
= U32 (extension
->ae_len
);
527 ad
= (struct grub_udf_short_ad
*)
528 (buf
+ sizeof (struct grub_udf_aed
));
532 if (filebytes
< adlen
)
534 grub_uint32_t ad_pos
= ad
->position
;
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
))));
544 len
-= sizeof (struct grub_udf_short_ad
);
549 struct grub_udf_long_ad
*ad
= (struct grub_udf_long_ad
*) ptr
;
551 filebytes
= fileblock
* U32 (node
->data
->lvd
.bsize
);
552 while (len
>= (grub_ssize_t
) sizeof (struct grub_udf_long_ad
))
554 grub_uint32_t adlen
= U32 (ad
->length
) & 0x3fffffff;
555 grub_uint32_t adtype
= U32 (ad
->length
) >> 30;
558 struct grub_udf_aed
*extension
;
559 grub_disk_addr_t sec
= grub_udf_get_block(node
->data
,
561 ad
->block
.block_num
);
564 buf
= grub_malloc (U32 (node
->data
->lvd
.bsize
));
568 if (grub_disk_read (node
->data
->disk
, sec
<< node
->data
->lbshift
,
572 extension
= (struct grub_udf_aed
*) buf
;
573 if (U16 (extension
->tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_AED
)
575 grub_error (GRUB_ERR_BAD_FS
, "invalid aed tag");
579 len
= U32 (extension
->ae_len
);
580 ad
= (struct grub_udf_long_ad
*)
581 (buf
+ sizeof (struct grub_udf_aed
));
585 if (filebytes
< adlen
)
587 grub_uint32_t ad_block_num
= ad
->block
.block_num
;
588 grub_uint32_t ad_part_ref
= ad
->block
.part_ref
;
590 return ((U32 (ad_block_num
) & GRUB_UDF_EXT_MASK
) ? 0 :
591 (grub_udf_get_block (node
->data
, ad_part_ref
,
593 + (filebytes
>> (GRUB_DISK_SECTOR_BITS
594 + node
->data
->lbshift
))));
599 len
-= sizeof (struct grub_udf_long_ad
);
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
)
614 switch (U16 (node
->block
.fe
.icbtag
.flags
) & GRUB_UDF_ICBTAG_FLAG_AD_MASK
)
616 case GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB
:
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
)));
626 grub_memcpy (buf
, ptr
+ pos
, len
);
631 case GRUB_UDF_ICBTAG_FLAG_AD_EXT
:
632 grub_error (GRUB_ERR_BAD_FS
, "invalid extent type");
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);
643 static unsigned sblocklist
[] = { 256, 512, 0 };
645 static struct grub_udf_data
*
646 grub_udf_mount (grub_disk_t disk
)
648 struct grub_udf_data
*data
= 0;
649 struct grub_udf_fileset root_fs
;
651 grub_uint32_t block
, vblock
;
654 data
= grub_malloc (sizeof (struct grub_udf_data
));
660 /* Search for Anchor Volume Descriptor Pointer (AVDP)
661 * and determine logical block size. */
663 for (lbshift
= 0; lbshift
< 4; lbshift
++)
665 for (sblklist
= sblocklist
; *sblklist
; sblklist
++)
667 struct grub_udf_avdp avdp
;
669 if (grub_disk_read (disk
, *sblklist
<< lbshift
, 0,
670 sizeof (struct grub_udf_avdp
), &avdp
))
672 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
676 if (U16 (avdp
.tag
.tag_ident
) == GRUB_UDF_TAG_IDENT_AVDP
&&
677 U32 (avdp
.tag
.tag_location
) == *sblklist
)
679 block
= U32 (avdp
.vds
.start
);
690 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
693 data
->lbshift
= lbshift
;
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)
699 struct grub_udf_vrs vrs
;
701 if (grub_disk_read (disk
, vblock
<< lbshift
, 0,
702 sizeof (struct grub_udf_vrs
), &vrs
))
704 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
708 if ((!grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_NSR03
, 5)) ||
709 (!grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_NSR02
, 5)))
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)))
718 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
723 data
->npd
= data
->npm
= 0;
724 /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD). */
727 struct grub_udf_tag tag
;
729 if (grub_disk_read (disk
, block
<< lbshift
, 0,
730 sizeof (struct grub_udf_tag
), &tag
))
732 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
736 tag
.tag_ident
= U16 (tag
.tag_ident
);
737 if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_PVD
)
739 if (grub_disk_read (disk
, block
<< lbshift
, 0,
740 sizeof (struct grub_udf_pvd
),
743 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
747 else if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_PD
)
749 if (data
->npd
>= GRUB_UDF_MAX_PDS
)
751 grub_error (GRUB_ERR_BAD_FS
, "too many PDs");
755 if (grub_disk_read (disk
, block
<< lbshift
, 0,
756 sizeof (struct grub_udf_pd
),
757 &data
->pds
[data
->npd
]))
759 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
763 g_last_pd_length_offset
= (block
<< lbshift
) * 512 + OFFSET_OF(struct grub_udf_pd
, length
);
767 else if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_LVD
)
771 struct grub_udf_partmap
*ppm
;
773 if (grub_disk_read (disk
, block
<< lbshift
, 0,
774 sizeof (struct grub_udf_lvd
),
777 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
781 if (data
->npm
+ U32 (data
->lvd
.num_part_maps
) > GRUB_UDF_MAX_PMS
)
783 grub_error (GRUB_ERR_BAD_FS
, "too many partition maps");
787 ppm
= (struct grub_udf_partmap
*) &data
->lvd
.part_maps
;
788 for (k
= U32 (data
->lvd
.num_part_maps
); k
> 0; k
--)
790 if (ppm
->type
!= GRUB_UDF_PARTMAP_TYPE_1
)
792 grub_error (GRUB_ERR_BAD_FS
, "partmap type not supported");
796 data
->pms
[data
->npm
++] = ppm
;
797 ppm
= (struct grub_udf_partmap
*) ((char *) ppm
+
801 else if (tag
.tag_ident
> GRUB_UDF_TAG_IDENT_TD
)
803 grub_error (GRUB_ERR_BAD_FS
, "invalid tag ident");
806 else if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_TD
)
812 for (i
= 0; i
< data
->npm
; i
++)
816 for (j
= 0; j
< data
->npd
; j
++)
817 if (data
->pms
[i
]->type1
.part_num
== data
->pds
[j
].part_num
)
819 data
->pms
[i
]->type1
.part_num
= j
;
825 grub_error (GRUB_ERR_BAD_FS
, "can\'t find PD");
830 block
= grub_udf_get_block (data
,
831 data
->lvd
.root_fileset
.block
.part_ref
,
832 data
->lvd
.root_fileset
.block
.block_num
);
837 if (grub_disk_read (disk
, block
<< lbshift
, 0,
838 sizeof (struct grub_udf_fileset
), &root_fs
))
840 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
844 if (U16 (root_fs
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_FSD
)
846 grub_error (GRUB_ERR_BAD_FS
, "invalid fileset descriptor");
850 data
->root_icb
= root_fs
.root_icb
;
861 grub_udf_get_cluster_sector (grub_disk_t disk
, grub_uint64_t
*sec_per_lcn
)
863 grub_disk_addr_t ret
;
864 static struct grub_udf_data
*data
;
866 data
= grub_udf_mount (disk
);
870 ret
= U32 (data
->pds
[data
->pms
[0]->type1
.part_num
].start
);
871 *sec_per_lcn
= 1ULL << data
->lbshift
;
878 read_string (const grub_uint8_t
*raw
, grub_size_t sz
, char *outbuf
)
880 grub_uint16_t
*utf16
= NULL
;
881 grub_size_t utf16len
= 0;
886 if (raw
[0] != 8 && raw
[0] != 16)
893 utf16
= grub_malloc (utf16len
* sizeof (utf16
[0]));
896 for (i
= 0; i
< utf16len
; i
++)
897 utf16
[i
] = raw
[i
+ 1];
902 utf16len
= (sz
- 1) / 2;
903 utf16
= grub_malloc (utf16len
* sizeof (utf16
[0]));
906 for (i
= 0; i
< utf16len
; i
++)
907 utf16
[i
] = (raw
[2 * i
+ 1] << 8) | raw
[2*i
+ 2];
910 outbuf
= grub_malloc (utf16len
* GRUB_MAX_UTF8_PER_UTF16
+ 1);
912 *grub_utf16_to_utf8 ((grub_uint8_t
*) outbuf
, utf16
, utf16len
) = '\0';
918 read_dstring (const grub_uint8_t
*raw
, grub_size_t sz
)
923 char *outbuf
= grub_malloc (1);
933 return read_string (raw
, len
, NULL
);
937 grub_udf_iterate_dir (grub_fshelp_node_t dir
,
938 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
940 grub_fshelp_node_t child
;
941 struct grub_udf_file_ident dirent
;
942 grub_off_t offset
= 0;
944 child
= grub_malloc (get_fshelp_size (dir
->data
));
948 /* The current directory is not stored. */
949 grub_memcpy (child
, dir
, get_fshelp_size (dir
->data
));
951 if (hook (".", GRUB_FSHELP_DIR
, child
, hook_data
))
954 while (offset
< U64 (dir
->block
.fe
.file_size
))
956 if (grub_udf_read_file (dir
, 0, 0, offset
, sizeof (dirent
),
957 (char *) &dirent
) != sizeof (dirent
))
960 if (U16 (dirent
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_FID
)
962 grub_error (GRUB_ERR_BAD_FS
, "invalid fid tag");
966 offset
+= sizeof (dirent
) + U16 (dirent
.imp_use_length
);
967 if (!(dirent
.characteristics
& GRUB_UDF_FID_CHAR_DELETED
))
969 child
= grub_malloc (get_fshelp_size (dir
->data
));
973 if (grub_udf_read_icb (dir
->data
, &dirent
.icb
, child
))
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
)
980 /* This is the parent directory. */
981 if (hook ("..", GRUB_FSHELP_DIR
, child
, hook_data
))
986 enum grub_fshelp_filetype type
;
988 grub_uint8_t raw
[MAX_FILE_IDENT_LENGTH
];
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
;
995 if ((grub_udf_read_file (dir
, 0, 0, offset
,
996 dirent
.file_ident_length
,
998 != dirent
.file_ident_length
)
1001 filename
= read_string (raw
, dirent
.file_ident_length
, 0);
1003 grub_print_error ();
1005 if (filename
&& hook (filename
, type
, child
, hook_data
))
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
);
1013 grub_free (filename
);
1017 /* Align to dword boundary. */
1018 offset
= (offset
+ dirent
.file_ident_length
+ 3) & (~3);
1025 grub_udf_read_symlink (grub_fshelp_node_t node
)
1027 grub_size_t sz
= U64 (node
->block
.fe
.file_size
);
1029 const grub_uint8_t
*ptr
;
1034 raw
= grub_malloc (sz
);
1037 if (grub_udf_read_file (node
, NULL
, NULL
, 0, sz
, (char *) raw
) < 0)
1043 out
= grub_malloc (sz
* 2 + 1);
1052 for (ptr
= raw
; ptr
< raw
+ sz
; )
1055 if ((grub_size_t
) (ptr
- raw
+ 4) > sz
)
1057 if (!(ptr
[2] == 0 && ptr
[3] == 0))
1060 if ((grub_size_t
) (ptr
- raw
+ s
) > sz
)
1069 /* in 4 bytes. out: 1 byte. */
1074 /* in 4 bytes. out: 3 bytes. */
1081 /* in 4 bytes. out: 2 bytes. */
1087 /* in 4 + n bytes. out, at most: 1 + 2 * n bytes. */
1090 if (!read_string (ptr
+ 4, s
- 4, optr
))
1092 optr
+= grub_strlen (optr
);
1106 grub_error (GRUB_ERR_BAD_FS
, "invalid symlink");
1110 /* Context for grub_udf_dir. */
1111 struct grub_udf_dir_ctx
1113 grub_fs_dir_hook_t hook
;
1117 /* Helper for grub_udf_dir. */
1119 grub_udf_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
1120 grub_fshelp_node_t node
, void *data
)
1122 struct grub_udf_dir_ctx
*ctx
= data
;
1123 struct grub_dirhook_info info
;
1124 const struct grub_udf_timestamp
*tstamp
= NULL
;
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
;
1133 if (tstamp
&& (U16 (tstamp
->type_and_timezone
) & 0xf000) == 0x1000)
1136 struct grub_datetime datetime
;
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
;
1145 tz
= U16 (tstamp
->type_and_timezone
) & 0xfff;
1151 info
.mtimeset
= !!grub_datetime2unixtime (&datetime
, &info
.mtime
);
1153 info
.mtime
-= 60 * tz
;
1156 info
.size
= U64 (node
->block
.fe
.file_size
);
1158 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
1162 grub_udf_dir (grub_device_t device
, const char *path
,
1163 grub_fs_dir_hook_t hook
, void *hook_data
)
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;
1170 grub_dl_ref (my_mod
);
1172 data
= grub_udf_mount (device
->disk
);
1176 rootnode
= grub_malloc (get_fshelp_size (data
));
1180 if (grub_udf_read_icb (data
, &data
->root_icb
, rootnode
))
1183 if (grub_fshelp_find_file (path
, rootnode
,
1185 grub_udf_iterate_dir
, grub_udf_read_symlink
,
1189 grub_udf_iterate_dir (foundnode
, grub_udf_dir_iter
, &ctx
);
1191 if (foundnode
!= rootnode
)
1192 grub_free (foundnode
);
1195 grub_free (rootnode
);
1199 grub_dl_unref (my_mod
);
1205 grub_udf_open (struct grub_file
*file
, const char *name
)
1207 struct grub_udf_data
*data
;
1208 struct grub_fshelp_node
*rootnode
= 0;
1209 struct grub_fshelp_node
*foundnode
;
1211 grub_dl_ref (my_mod
);
1213 data
= grub_udf_mount (file
->device
->disk
);
1217 rootnode
= grub_malloc (get_fshelp_size (data
));
1221 if (grub_udf_read_icb (data
, &data
->root_icb
, rootnode
))
1224 if (grub_fshelp_find_file (name
, rootnode
,
1226 grub_udf_iterate_dir
, grub_udf_read_symlink
,
1230 file
->data
= foundnode
;
1232 file
->size
= U64 (foundnode
->block
.fe
.file_size
);
1234 grub_free (rootnode
);
1239 grub_dl_unref (my_mod
);
1242 grub_free (rootnode
);
1248 grub_udf_read (grub_file_t file
, char *buf
, grub_size_t len
)
1250 struct grub_fshelp_node
*node
= (struct grub_fshelp_node
*) file
->data
;
1252 return grub_udf_read_file (node
, file
->read_hook
, file
->read_hook_data
,
1253 file
->offset
, len
, buf
);
1257 grub_udf_close (grub_file_t file
)
1261 struct grub_fshelp_node
*node
= (struct grub_fshelp_node
*) file
->data
;
1263 grub_free (node
->data
);
1267 grub_dl_unref (my_mod
);
1269 return GRUB_ERR_NONE
;
1273 grub_udf_label (grub_device_t device
, char **label
)
1275 struct grub_udf_data
*data
;
1276 data
= grub_udf_mount (device
->disk
);
1280 *label
= read_dstring (data
->lvd
.ident
, sizeof (data
->lvd
.ident
));
1290 gen_uuid_from_volset (char *volset_ident
)
1294 grub_size_t nonhexpos
;
1295 grub_uint8_t buf
[17];
1298 len
= grub_strlen (volset_ident
);
1302 uuid
= grub_malloc (17);
1309 grub_memset (buf
, 0, sizeof (buf
));
1310 grub_memcpy (buf
, volset_ident
, len
);
1313 for (i
= 0; i
< 16; ++i
)
1315 if (!grub_isxdigit (buf
[i
]))
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]);
1328 else if (nonhexpos
< 16)
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]);
1337 for (i
= 0; i
< 16; ++i
)
1338 uuid
[i
] = grub_tolower (buf
[i
]);
1346 grub_udf_uuid (grub_device_t device
, char **uuid
)
1349 struct grub_udf_data
*data
;
1350 data
= grub_udf_mount (device
->disk
);
1354 volset_ident
= read_dstring (data
->pvd
.volset_ident
, sizeof (data
->pvd
.volset_ident
));
1357 *uuid
= gen_uuid_from_volset (volset_ident
);
1358 grub_free (volset_ident
);
1370 grub_uint64_t
grub_udf_get_file_offset(grub_file_t file
)
1372 grub_disk_addr_t sector
;
1373 struct grub_fshelp_node
*node
= (struct grub_fshelp_node
*)file
->data
;
1375 sector
= grub_udf_read_block(node
, 0);
1377 return 512 * (sector
<< node
->data
->lbshift
);
1380 grub_uint64_t
grub_udf_get_last_pd_size_offset(void)
1382 return g_last_pd_length_offset
;
1385 grub_uint64_t grub_udf_get_last_file_attr_offset
1388 grub_uint32_t
*startBlock
,
1389 grub_uint64_t
*fe_entry_size_offset
1392 grub_uint64_t attr_offset
;
1393 struct grub_fshelp_node
*node
;
1394 struct grub_udf_data
*data
;
1396 node
= (struct grub_fshelp_node
*)file
->data
;
1399 *startBlock
= data
->pds
[data
->pms
[0]->type1
.part_num
].start
;
1401 attr_offset
= g_last_fileattr_read_sector
* 2048 + g_last_fileattr_offset
;
1403 if (GRUB_UDF_TAG_IDENT_FE
== g_last_fileattr_read_sector_tag_ident
)
1405 *fe_entry_size_offset
= g_last_fileattr_read_sector
* 2048 + OFFSET_OF(struct grub_udf_file_entry
, file_size
);
1409 *fe_entry_size_offset
= g_last_fileattr_read_sector
* 2048 + OFFSET_OF(struct grub_udf_extended_file_entry
, file_size
);
1415 static struct grub_fs grub_udf_fs
= {
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
,
1424 .reserved_first_sector
= 1,
1425 .blocklist_install
= 1,
1432 grub_fs_register (&grub_udf_fs
);
1438 grub_fs_unregister (&grub_udf_fs
);