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>
32 GRUB_MOD_LICENSE ("GPLv3+");
34 #define GRUB_UDF_MAX_PDS 2
35 #define GRUB_UDF_MAX_PMS 6
37 #define U16 grub_le_to_cpu16
38 #define U32 grub_le_to_cpu32
39 #define U64 grub_le_to_cpu64
41 #define GRUB_UDF_TAG_IDENT_PVD 0x0001
42 #define GRUB_UDF_TAG_IDENT_AVDP 0x0002
43 #define GRUB_UDF_TAG_IDENT_VDP 0x0003
44 #define GRUB_UDF_TAG_IDENT_IUVD 0x0004
45 #define GRUB_UDF_TAG_IDENT_PD 0x0005
46 #define GRUB_UDF_TAG_IDENT_LVD 0x0006
47 #define GRUB_UDF_TAG_IDENT_USD 0x0007
48 #define GRUB_UDF_TAG_IDENT_TD 0x0008
49 #define GRUB_UDF_TAG_IDENT_LVID 0x0009
51 #define GRUB_UDF_TAG_IDENT_FSD 0x0100
52 #define GRUB_UDF_TAG_IDENT_FID 0x0101
53 #define GRUB_UDF_TAG_IDENT_AED 0x0102
54 #define GRUB_UDF_TAG_IDENT_IE 0x0103
55 #define GRUB_UDF_TAG_IDENT_TE 0x0104
56 #define GRUB_UDF_TAG_IDENT_FE 0x0105
57 #define GRUB_UDF_TAG_IDENT_EAHD 0x0106
58 #define GRUB_UDF_TAG_IDENT_USE 0x0107
59 #define GRUB_UDF_TAG_IDENT_SBD 0x0108
60 #define GRUB_UDF_TAG_IDENT_PIE 0x0109
61 #define GRUB_UDF_TAG_IDENT_EFE 0x010A
63 #define GRUB_UDF_ICBTAG_TYPE_UNDEF 0x00
64 #define GRUB_UDF_ICBTAG_TYPE_USE 0x01
65 #define GRUB_UDF_ICBTAG_TYPE_PIE 0x02
66 #define GRUB_UDF_ICBTAG_TYPE_IE 0x03
67 #define GRUB_UDF_ICBTAG_TYPE_DIRECTORY 0x04
68 #define GRUB_UDF_ICBTAG_TYPE_REGULAR 0x05
69 #define GRUB_UDF_ICBTAG_TYPE_BLOCK 0x06
70 #define GRUB_UDF_ICBTAG_TYPE_CHAR 0x07
71 #define GRUB_UDF_ICBTAG_TYPE_EA 0x08
72 #define GRUB_UDF_ICBTAG_TYPE_FIFO 0x09
73 #define GRUB_UDF_ICBTAG_TYPE_SOCKET 0x0A
74 #define GRUB_UDF_ICBTAG_TYPE_TE 0x0B
75 #define GRUB_UDF_ICBTAG_TYPE_SYMLINK 0x0C
76 #define GRUB_UDF_ICBTAG_TYPE_STREAMDIR 0x0D
78 #define GRUB_UDF_ICBTAG_FLAG_AD_MASK 0x0007
79 #define GRUB_UDF_ICBTAG_FLAG_AD_SHORT 0x0000
80 #define GRUB_UDF_ICBTAG_FLAG_AD_LONG 0x0001
81 #define GRUB_UDF_ICBTAG_FLAG_AD_EXT 0x0002
82 #define GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB 0x0003
84 #define GRUB_UDF_EXT_NORMAL 0x00000000
85 #define GRUB_UDF_EXT_NREC_ALLOC 0x40000000
86 #define GRUB_UDF_EXT_NREC_NALLOC 0x80000000
87 #define GRUB_UDF_EXT_MASK 0xC0000000
89 #define GRUB_UDF_FID_CHAR_HIDDEN 0x01
90 #define GRUB_UDF_FID_CHAR_DIRECTORY 0x02
91 #define GRUB_UDF_FID_CHAR_DELETED 0x04
92 #define GRUB_UDF_FID_CHAR_PARENT 0x08
93 #define GRUB_UDF_FID_CHAR_METADATA 0x10
95 #define GRUB_UDF_STD_IDENT_BEA01 "BEA01"
96 #define GRUB_UDF_STD_IDENT_BOOT2 "BOOT2"
97 #define GRUB_UDF_STD_IDENT_CD001 "CD001"
98 #define GRUB_UDF_STD_IDENT_CDW02 "CDW02"
99 #define GRUB_UDF_STD_IDENT_NSR02 "NSR02"
100 #define GRUB_UDF_STD_IDENT_NSR03 "NSR03"
101 #define GRUB_UDF_STD_IDENT_TEA01 "TEA01"
103 #define GRUB_UDF_CHARSPEC_TYPE_CS0 0x00
104 #define GRUB_UDF_CHARSPEC_TYPE_CS1 0x01
105 #define GRUB_UDF_CHARSPEC_TYPE_CS2 0x02
106 #define GRUB_UDF_CHARSPEC_TYPE_CS3 0x03
107 #define GRUB_UDF_CHARSPEC_TYPE_CS4 0x04
108 #define GRUB_UDF_CHARSPEC_TYPE_CS5 0x05
109 #define GRUB_UDF_CHARSPEC_TYPE_CS6 0x06
110 #define GRUB_UDF_CHARSPEC_TYPE_CS7 0x07
111 #define GRUB_UDF_CHARSPEC_TYPE_CS8 0x08
113 #define GRUB_UDF_PARTMAP_TYPE_1 1
114 #define GRUB_UDF_PARTMAP_TYPE_2 2
116 struct grub_udf_lb_addr
118 grub_uint32_t block_num
;
119 grub_uint16_t part_ref
;
122 struct grub_udf_short_ad
124 grub_uint32_t length
;
125 grub_uint32_t position
;
128 struct grub_udf_long_ad
130 grub_uint32_t length
;
131 struct grub_udf_lb_addr block
;
132 grub_uint8_t imp_use
[6];
135 struct grub_udf_extent_ad
137 grub_uint32_t length
;
141 struct grub_udf_charspec
143 grub_uint8_t charset_type
;
144 grub_uint8_t charset_info
[63];
147 struct grub_udf_timestamp
149 grub_uint16_t type_and_timezone
;
156 grub_uint8_t centi_seconds
;
157 grub_uint8_t hundreds_of_micro_seconds
;
158 grub_uint8_t micro_seconds
;
161 struct grub_udf_regid
164 grub_uint8_t ident
[23];
165 grub_uint8_t ident_suffix
[8];
170 grub_uint16_t tag_ident
;
171 grub_uint16_t desc_version
;
172 grub_uint8_t tag_checksum
;
173 grub_uint8_t reserved
;
174 grub_uint16_t tag_serial_number
;
175 grub_uint16_t desc_crc
;
176 grub_uint16_t desc_crc_length
;
177 grub_uint32_t tag_location
;
180 struct grub_udf_fileset
182 struct grub_udf_tag tag
;
183 struct grub_udf_timestamp datetime
;
184 grub_uint16_t interchange_level
;
185 grub_uint16_t max_interchange_level
;
186 grub_uint32_t charset_list
;
187 grub_uint32_t max_charset_list
;
188 grub_uint32_t fileset_num
;
189 grub_uint32_t fileset_desc_num
;
190 struct grub_udf_charspec vol_charset
;
191 grub_uint8_t vol_ident
[128];
192 struct grub_udf_charspec fileset_charset
;
193 grub_uint8_t fileset_ident
[32];
194 grub_uint8_t copyright_file_ident
[32];
195 grub_uint8_t abstract_file_ident
[32];
196 struct grub_udf_long_ad root_icb
;
197 struct grub_udf_regid domain_ident
;
198 struct grub_udf_long_ad next_ext
;
199 struct grub_udf_long_ad streamdir_icb
;
202 struct grub_udf_icbtag
204 grub_uint32_t prior_recorded_num_direct_entries
;
205 grub_uint16_t strategy_type
;
206 grub_uint16_t strategy_parameter
;
207 grub_uint16_t num_entries
;
208 grub_uint8_t reserved
;
209 grub_uint8_t file_type
;
210 struct grub_udf_lb_addr parent_idb
;
214 struct grub_udf_file_ident
216 struct grub_udf_tag tag
;
217 grub_uint16_t version_num
;
218 grub_uint8_t characteristics
;
219 #define MAX_FILE_IDENT_LENGTH 256
220 grub_uint8_t file_ident_length
;
221 struct grub_udf_long_ad icb
;
222 grub_uint16_t imp_use_length
;
225 struct grub_udf_file_entry
227 struct grub_udf_tag tag
;
228 struct grub_udf_icbtag icbtag
;
231 grub_uint32_t permissions
;
232 grub_uint16_t link_count
;
233 grub_uint8_t record_format
;
234 grub_uint8_t record_display_attr
;
235 grub_uint32_t record_length
;
236 grub_uint64_t file_size
;
237 grub_uint64_t blocks_recorded
;
238 struct grub_udf_timestamp access_time
;
239 struct grub_udf_timestamp modification_time
;
240 struct grub_udf_timestamp attr_time
;
241 grub_uint32_t checkpoint
;
242 struct grub_udf_long_ad extended_attr_idb
;
243 struct grub_udf_regid imp_ident
;
244 grub_uint64_t unique_id
;
245 grub_uint32_t ext_attr_length
;
246 grub_uint32_t alloc_descs_length
;
247 grub_uint8_t ext_attr
[0];
250 struct grub_udf_extended_file_entry
252 struct grub_udf_tag tag
;
253 struct grub_udf_icbtag icbtag
;
256 grub_uint32_t permissions
;
257 grub_uint16_t link_count
;
258 grub_uint8_t record_format
;
259 grub_uint8_t record_display_attr
;
260 grub_uint32_t record_length
;
261 grub_uint64_t file_size
;
262 grub_uint64_t object_size
;
263 grub_uint64_t blocks_recorded
;
264 struct grub_udf_timestamp access_time
;
265 struct grub_udf_timestamp modification_time
;
266 struct grub_udf_timestamp create_time
;
267 struct grub_udf_timestamp attr_time
;
268 grub_uint32_t checkpoint
;
269 grub_uint32_t reserved
;
270 struct grub_udf_long_ad extended_attr_icb
;
271 struct grub_udf_long_ad streamdir_icb
;
272 struct grub_udf_regid imp_ident
;
273 grub_uint64_t unique_id
;
274 grub_uint32_t ext_attr_length
;
275 grub_uint32_t alloc_descs_length
;
276 grub_uint8_t ext_attr
[0];
282 grub_uint8_t magic
[5];
283 grub_uint8_t version
;
288 struct grub_udf_tag tag
;
289 struct grub_udf_extent_ad vds
;
294 struct grub_udf_tag tag
;
295 grub_uint32_t seq_num
;
297 grub_uint16_t part_num
;
298 struct grub_udf_regid contents
;
299 grub_uint8_t contents_use
[128];
300 grub_uint32_t access_type
;
302 grub_uint32_t length
;
305 struct grub_udf_partmap
313 grub_uint16_t seq_num
;
314 grub_uint16_t part_num
;
319 grub_uint8_t ident
[62];
326 struct grub_udf_tag tag
;
327 grub_uint32_t seq_num
;
328 struct grub_udf_charspec charset
;
329 grub_uint8_t ident
[128];
331 struct grub_udf_regid domain_ident
;
332 struct grub_udf_long_ad root_fileset
;
333 grub_uint32_t map_table_length
;
334 grub_uint32_t num_part_maps
;
335 struct grub_udf_regid imp_ident
;
336 grub_uint8_t imp_use
[128];
337 struct grub_udf_extent_ad integrity_seq_ext
;
338 grub_uint8_t part_maps
[1608];
343 struct grub_udf_tag tag
;
344 grub_uint32_t prev_ae
;
345 grub_uint32_t ae_len
;
351 struct grub_udf_lvd lvd
;
352 struct grub_udf_pd pds
[GRUB_UDF_MAX_PDS
];
353 struct grub_udf_partmap
*pms
[GRUB_UDF_MAX_PMS
];
354 struct grub_udf_long_ad root_icb
;
355 int npd
, npm
, lbshift
;
358 struct grub_fshelp_node
360 struct grub_udf_data
*data
;
364 struct grub_udf_file_entry fe
;
365 struct grub_udf_extended_file_entry efe
;
370 static inline grub_size_t
371 get_fshelp_size (struct grub_udf_data
*data
)
373 struct grub_fshelp_node
*x
= NULL
;
375 + (1 << (GRUB_DISK_SECTOR_BITS
376 + data
->lbshift
)) - sizeof (x
->block
);
379 static grub_dl_t my_mod
;
382 grub_udf_get_block (struct grub_udf_data
*data
,
383 grub_uint16_t part_ref
, grub_uint32_t block
)
385 part_ref
= U16 (part_ref
);
387 if (part_ref
>= data
->npm
)
389 grub_error (GRUB_ERR_BAD_FS
, "invalid part ref");
393 return (U32 (data
->pds
[data
->pms
[part_ref
]->type1
.part_num
].start
)
398 grub_udf_read_icb (struct grub_udf_data
*data
,
399 struct grub_udf_long_ad
*icb
,
400 struct grub_fshelp_node
*node
)
404 block
= grub_udf_get_block (data
,
406 icb
->block
.block_num
);
411 if (grub_disk_read (data
->disk
, block
<< data
->lbshift
, 0,
412 1 << (GRUB_DISK_SECTOR_BITS
417 if ((U16 (node
->block
.fe
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_FE
) &&
418 (U16 (node
->block
.fe
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_EFE
))
419 return grub_error (GRUB_ERR_BAD_FS
, "invalid fe/efe descriptor");
421 node
->part_ref
= icb
->block
.part_ref
;
426 static grub_disk_addr_t
427 grub_udf_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
432 grub_disk_addr_t filebytes
;
434 switch (U16 (node
->block
.fe
.tag
.tag_ident
))
436 case GRUB_UDF_TAG_IDENT_FE
:
437 ptr
= (char *) &node
->block
.fe
.ext_attr
[0] + U32 (node
->block
.fe
.ext_attr_length
);
438 len
= U32 (node
->block
.fe
.alloc_descs_length
);
441 case GRUB_UDF_TAG_IDENT_EFE
:
442 ptr
= (char *) &node
->block
.efe
.ext_attr
[0] + U32 (node
->block
.efe
.ext_attr_length
);
443 len
= U32 (node
->block
.efe
.alloc_descs_length
);
447 grub_error (GRUB_ERR_BAD_FS
, "invalid file entry");
451 if ((U16 (node
->block
.fe
.icbtag
.flags
) & GRUB_UDF_ICBTAG_FLAG_AD_MASK
)
452 == GRUB_UDF_ICBTAG_FLAG_AD_SHORT
)
454 struct grub_udf_short_ad
*ad
= (struct grub_udf_short_ad
*) ptr
;
456 filebytes
= fileblock
* U32 (node
->data
->lvd
.bsize
);
457 while (len
>= (grub_ssize_t
) sizeof (struct grub_udf_short_ad
))
459 grub_uint32_t adlen
= U32 (ad
->length
) & 0x3fffffff;
460 grub_uint32_t adtype
= U32 (ad
->length
) >> 30;
463 struct grub_udf_aed
*extension
;
464 grub_disk_addr_t sec
= grub_udf_get_block(node
->data
,
469 buf
= grub_malloc (U32 (node
->data
->lvd
.bsize
));
473 if (grub_disk_read (node
->data
->disk
, sec
<< node
->data
->lbshift
,
477 extension
= (struct grub_udf_aed
*) buf
;
478 if (U16 (extension
->tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_AED
)
480 grub_error (GRUB_ERR_BAD_FS
, "invalid aed tag");
484 len
= U32 (extension
->ae_len
);
485 ad
= (struct grub_udf_short_ad
*)
486 (buf
+ sizeof (struct grub_udf_aed
));
490 if (filebytes
< adlen
)
492 grub_uint32_t ad_pos
= ad
->position
;
494 return ((U32 (ad_pos
) & GRUB_UDF_EXT_MASK
) ? 0 :
495 (grub_udf_get_block (node
->data
, node
->part_ref
, ad_pos
)
496 + (filebytes
>> (GRUB_DISK_SECTOR_BITS
497 + node
->data
->lbshift
))));
502 len
-= sizeof (struct grub_udf_short_ad
);
507 struct grub_udf_long_ad
*ad
= (struct grub_udf_long_ad
*) ptr
;
509 filebytes
= fileblock
* U32 (node
->data
->lvd
.bsize
);
510 while (len
>= (grub_ssize_t
) sizeof (struct grub_udf_long_ad
))
512 grub_uint32_t adlen
= U32 (ad
->length
) & 0x3fffffff;
513 grub_uint32_t adtype
= U32 (ad
->length
) >> 30;
516 struct grub_udf_aed
*extension
;
517 grub_disk_addr_t sec
= grub_udf_get_block(node
->data
,
519 ad
->block
.block_num
);
522 buf
= grub_malloc (U32 (node
->data
->lvd
.bsize
));
526 if (grub_disk_read (node
->data
->disk
, sec
<< node
->data
->lbshift
,
530 extension
= (struct grub_udf_aed
*) buf
;
531 if (U16 (extension
->tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_AED
)
533 grub_error (GRUB_ERR_BAD_FS
, "invalid aed tag");
537 len
= U32 (extension
->ae_len
);
538 ad
= (struct grub_udf_long_ad
*)
539 (buf
+ sizeof (struct grub_udf_aed
));
543 if (filebytes
< adlen
)
545 grub_uint32_t ad_block_num
= ad
->block
.block_num
;
546 grub_uint32_t ad_part_ref
= ad
->block
.part_ref
;
548 return ((U32 (ad_block_num
) & GRUB_UDF_EXT_MASK
) ? 0 :
549 (grub_udf_get_block (node
->data
, ad_part_ref
,
551 + (filebytes
>> (GRUB_DISK_SECTOR_BITS
552 + node
->data
->lbshift
))));
557 len
-= sizeof (struct grub_udf_long_ad
);
568 grub_udf_read_file (grub_fshelp_node_t node
,
569 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
570 grub_off_t pos
, grub_size_t len
, char *buf
)
572 switch (U16 (node
->block
.fe
.icbtag
.flags
) & GRUB_UDF_ICBTAG_FLAG_AD_MASK
)
574 case GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB
:
578 ptr
= ((U16 (node
->block
.fe
.tag
.tag_ident
) == GRUB_UDF_TAG_IDENT_FE
) ?
579 ((char *) &node
->block
.fe
.ext_attr
[0]
580 + U32 (node
->block
.fe
.ext_attr_length
)) :
581 ((char *) &node
->block
.efe
.ext_attr
[0]
582 + U32 (node
->block
.efe
.ext_attr_length
)));
584 grub_memcpy (buf
, ptr
+ pos
, len
);
589 case GRUB_UDF_ICBTAG_FLAG_AD_EXT
:
590 grub_error (GRUB_ERR_BAD_FS
, "invalid extent type");
594 return grub_fshelp_read_file (node
->data
->disk
, node
,
595 read_hook
, read_hook_data
,
596 pos
, len
, buf
, grub_udf_read_block
,
597 U64 (node
->block
.fe
.file_size
),
598 node
->data
->lbshift
, 0);
601 static unsigned sblocklist
[] = { 256, 512, 0 };
603 static struct grub_udf_data
*
604 grub_udf_mount (grub_disk_t disk
)
606 struct grub_udf_data
*data
= 0;
607 struct grub_udf_fileset root_fs
;
609 grub_uint32_t block
, vblock
;
612 data
= grub_malloc (sizeof (struct grub_udf_data
));
618 /* Search for Anchor Volume Descriptor Pointer (AVDP)
619 * and determine logical block size. */
621 for (lbshift
= 0; lbshift
< 4; lbshift
++)
623 for (sblklist
= sblocklist
; *sblklist
; sblklist
++)
625 struct grub_udf_avdp avdp
;
627 if (grub_disk_read (disk
, *sblklist
<< lbshift
, 0,
628 sizeof (struct grub_udf_avdp
), &avdp
))
630 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
634 if (U16 (avdp
.tag
.tag_ident
) == GRUB_UDF_TAG_IDENT_AVDP
&&
635 U32 (avdp
.tag
.tag_location
) == *sblklist
)
637 block
= U32 (avdp
.vds
.start
);
648 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
651 data
->lbshift
= lbshift
;
653 /* Search for Volume Recognition Sequence (VRS). */
654 for (vblock
= (32767 >> (lbshift
+ GRUB_DISK_SECTOR_BITS
)) + 1;;
655 vblock
+= (2047 >> (lbshift
+ GRUB_DISK_SECTOR_BITS
)) + 1)
657 struct grub_udf_vrs vrs
;
659 if (grub_disk_read (disk
, vblock
<< lbshift
, 0,
660 sizeof (struct grub_udf_vrs
), &vrs
))
662 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
666 if ((!grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_NSR03
, 5)) ||
667 (!grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_NSR02
, 5)))
670 if ((grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_BEA01
, 5)) &&
671 (grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_BOOT2
, 5)) &&
672 (grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_CD001
, 5)) &&
673 (grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_CDW02
, 5)) &&
674 (grub_memcmp (vrs
.magic
, GRUB_UDF_STD_IDENT_TEA01
, 5)))
676 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
681 data
->npd
= data
->npm
= 0;
682 /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD). */
685 struct grub_udf_tag tag
;
687 if (grub_disk_read (disk
, block
<< lbshift
, 0,
688 sizeof (struct grub_udf_tag
), &tag
))
690 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
694 tag
.tag_ident
= U16 (tag
.tag_ident
);
695 if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_PD
)
697 if (data
->npd
>= GRUB_UDF_MAX_PDS
)
699 grub_error (GRUB_ERR_BAD_FS
, "too many PDs");
703 if (grub_disk_read (disk
, block
<< lbshift
, 0,
704 sizeof (struct grub_udf_pd
),
705 &data
->pds
[data
->npd
]))
707 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
713 else if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_LVD
)
717 struct grub_udf_partmap
*ppm
;
719 if (grub_disk_read (disk
, block
<< lbshift
, 0,
720 sizeof (struct grub_udf_lvd
),
723 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
727 if (data
->npm
+ U32 (data
->lvd
.num_part_maps
) > GRUB_UDF_MAX_PMS
)
729 grub_error (GRUB_ERR_BAD_FS
, "too many partition maps");
733 ppm
= (struct grub_udf_partmap
*) &data
->lvd
.part_maps
;
734 for (k
= U32 (data
->lvd
.num_part_maps
); k
> 0; k
--)
736 if (ppm
->type
!= GRUB_UDF_PARTMAP_TYPE_1
)
738 grub_error (GRUB_ERR_BAD_FS
, "partmap type not supported");
742 data
->pms
[data
->npm
++] = ppm
;
743 ppm
= (struct grub_udf_partmap
*) ((char *) ppm
+
747 else if (tag
.tag_ident
> GRUB_UDF_TAG_IDENT_TD
)
749 grub_error (GRUB_ERR_BAD_FS
, "invalid tag ident");
752 else if (tag
.tag_ident
== GRUB_UDF_TAG_IDENT_TD
)
758 for (i
= 0; i
< data
->npm
; i
++)
762 for (j
= 0; j
< data
->npd
; j
++)
763 if (data
->pms
[i
]->type1
.part_num
== data
->pds
[j
].part_num
)
765 data
->pms
[i
]->type1
.part_num
= j
;
771 grub_error (GRUB_ERR_BAD_FS
, "can\'t find PD");
776 block
= grub_udf_get_block (data
,
777 data
->lvd
.root_fileset
.block
.part_ref
,
778 data
->lvd
.root_fileset
.block
.block_num
);
783 if (grub_disk_read (disk
, block
<< lbshift
, 0,
784 sizeof (struct grub_udf_fileset
), &root_fs
))
786 grub_error (GRUB_ERR_BAD_FS
, "not an UDF filesystem");
790 if (U16 (root_fs
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_FSD
)
792 grub_error (GRUB_ERR_BAD_FS
, "invalid fileset descriptor");
796 data
->root_icb
= root_fs
.root_icb
;
807 grub_udf_get_cluster_sector (grub_disk_t disk
, grub_uint64_t
*sec_per_lcn
)
809 grub_disk_addr_t ret
;
810 static struct grub_udf_data
*data
;
812 data
= grub_udf_mount (disk
);
816 ret
= U32 (data
->pds
[data
->pms
[0]->type1
.part_num
].start
);
817 *sec_per_lcn
= 1ULL << data
->lbshift
;
824 read_string (const grub_uint8_t
*raw
, grub_size_t sz
, char *outbuf
)
826 grub_uint16_t
*utf16
= NULL
;
827 grub_size_t utf16len
= 0;
832 if (raw
[0] != 8 && raw
[0] != 16)
839 utf16
= grub_malloc (utf16len
* sizeof (utf16
[0]));
842 for (i
= 0; i
< utf16len
; i
++)
843 utf16
[i
] = raw
[i
+ 1];
848 utf16len
= (sz
- 1) / 2;
849 utf16
= grub_malloc (utf16len
* sizeof (utf16
[0]));
852 for (i
= 0; i
< utf16len
; i
++)
853 utf16
[i
] = (raw
[2 * i
+ 1] << 8) | raw
[2*i
+ 2];
856 outbuf
= grub_malloc (utf16len
* GRUB_MAX_UTF8_PER_UTF16
+ 1);
858 *grub_utf16_to_utf8 ((grub_uint8_t
*) outbuf
, utf16
, utf16len
) = '\0';
864 grub_udf_iterate_dir (grub_fshelp_node_t dir
,
865 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
867 grub_fshelp_node_t child
;
868 struct grub_udf_file_ident dirent
;
869 grub_off_t offset
= 0;
871 child
= grub_malloc (get_fshelp_size (dir
->data
));
875 /* The current directory is not stored. */
876 grub_memcpy (child
, dir
, get_fshelp_size (dir
->data
));
878 if (hook (".", GRUB_FSHELP_DIR
, child
, hook_data
))
881 while (offset
< U64 (dir
->block
.fe
.file_size
))
883 if (grub_udf_read_file (dir
, 0, 0, offset
, sizeof (dirent
),
884 (char *) &dirent
) != sizeof (dirent
))
887 if (U16 (dirent
.tag
.tag_ident
) != GRUB_UDF_TAG_IDENT_FID
)
889 grub_error (GRUB_ERR_BAD_FS
, "invalid fid tag");
893 offset
+= sizeof (dirent
) + U16 (dirent
.imp_use_length
);
894 if (!(dirent
.characteristics
& GRUB_UDF_FID_CHAR_DELETED
))
896 child
= grub_malloc (get_fshelp_size (dir
->data
));
900 if (grub_udf_read_icb (dir
->data
, &dirent
.icb
, child
))
903 if (dirent
.characteristics
& GRUB_UDF_FID_CHAR_PARENT
)
905 /* This is the parent directory. */
906 if (hook ("..", GRUB_FSHELP_DIR
, child
, hook_data
))
911 enum grub_fshelp_filetype type
;
913 grub_uint8_t raw
[MAX_FILE_IDENT_LENGTH
];
915 type
= ((dirent
.characteristics
& GRUB_UDF_FID_CHAR_DIRECTORY
) ?
916 (GRUB_FSHELP_DIR
) : (GRUB_FSHELP_REG
));
917 if (child
->block
.fe
.icbtag
.file_type
== GRUB_UDF_ICBTAG_TYPE_SYMLINK
)
918 type
= GRUB_FSHELP_SYMLINK
;
920 if ((grub_udf_read_file (dir
, 0, 0, offset
,
921 dirent
.file_ident_length
,
923 != dirent
.file_ident_length
)
926 filename
= read_string (raw
, dirent
.file_ident_length
, 0);
930 if (filename
&& hook (filename
, type
, child
, hook_data
))
932 grub_free (filename
);
935 grub_free (filename
);
939 /* Align to dword boundary. */
940 offset
= (offset
+ dirent
.file_ident_length
+ 3) & (~3);
947 grub_udf_read_symlink (grub_fshelp_node_t node
)
949 grub_size_t sz
= U64 (node
->block
.fe
.file_size
);
951 const grub_uint8_t
*ptr
;
956 raw
= grub_malloc (sz
);
959 if (grub_udf_read_file (node
, NULL
, NULL
, 0, sz
, (char *) raw
) < 0)
965 out
= grub_malloc (sz
* 2 + 1);
974 for (ptr
= raw
; ptr
< raw
+ sz
; )
977 if ((grub_size_t
) (ptr
- raw
+ 4) > sz
)
979 if (!(ptr
[2] == 0 && ptr
[3] == 0))
982 if ((grub_size_t
) (ptr
- raw
+ s
) > sz
)
991 /* in 4 bytes. out: 1 byte. */
996 /* in 4 bytes. out: 3 bytes. */
1003 /* in 4 bytes. out: 2 bytes. */
1009 /* in 4 + n bytes. out, at most: 1 + 2 * n bytes. */
1012 if (!read_string (ptr
+ 4, s
- 4, optr
))
1014 optr
+= grub_strlen (optr
);
1028 grub_error (GRUB_ERR_BAD_FS
, "invalid symlink");
1032 /* Context for grub_udf_dir. */
1033 struct grub_udf_dir_ctx
1035 grub_fs_dir_hook_t hook
;
1039 /* Helper for grub_udf_dir. */
1041 grub_udf_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
1042 grub_fshelp_node_t node
, void *data
)
1044 struct grub_udf_dir_ctx
*ctx
= data
;
1045 struct grub_dirhook_info info
;
1046 const struct grub_udf_timestamp
*tstamp
= NULL
;
1048 grub_memset (&info
, 0, sizeof (info
));
1049 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
1050 if (U16 (node
->block
.fe
.tag
.tag_ident
) == GRUB_UDF_TAG_IDENT_FE
)
1051 tstamp
= &node
->block
.fe
.modification_time
;
1052 else if (U16 (node
->block
.fe
.tag
.tag_ident
) == GRUB_UDF_TAG_IDENT_EFE
)
1053 tstamp
= &node
->block
.efe
.modification_time
;
1055 if (tstamp
&& (U16 (tstamp
->type_and_timezone
) & 0xf000) == 0x1000)
1058 struct grub_datetime datetime
;
1060 datetime
.year
= U16 (tstamp
->year
);
1061 datetime
.month
= tstamp
->month
;
1062 datetime
.day
= tstamp
->day
;
1063 datetime
.hour
= tstamp
->hour
;
1064 datetime
.minute
= tstamp
->minute
;
1065 datetime
.second
= tstamp
->second
;
1067 tz
= U16 (tstamp
->type_and_timezone
) & 0xfff;
1073 info
.mtimeset
= !!grub_datetime2unixtime (&datetime
, &info
.mtime
);
1075 info
.mtime
-= 60 * tz
;
1078 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
1082 grub_udf_dir (grub_device_t device
, const char *path
,
1083 grub_fs_dir_hook_t hook
, void *hook_data
)
1085 struct grub_udf_dir_ctx ctx
= { hook
, hook_data
};
1086 struct grub_udf_data
*data
= 0;
1087 struct grub_fshelp_node
*rootnode
= 0;
1088 struct grub_fshelp_node
*foundnode
= 0;
1090 grub_dl_ref (my_mod
);
1092 data
= grub_udf_mount (device
->disk
);
1096 rootnode
= grub_malloc (get_fshelp_size (data
));
1100 if (grub_udf_read_icb (data
, &data
->root_icb
, rootnode
))
1103 if (grub_fshelp_find_file (path
, rootnode
,
1105 grub_udf_iterate_dir
, grub_udf_read_symlink
,
1109 grub_udf_iterate_dir (foundnode
, grub_udf_dir_iter
, &ctx
);
1111 if (foundnode
!= rootnode
)
1112 grub_free (foundnode
);
1115 grub_free (rootnode
);
1119 grub_dl_unref (my_mod
);
1125 grub_udf_open (struct grub_file
*file
, const char *name
)
1127 struct grub_udf_data
*data
;
1128 struct grub_fshelp_node
*rootnode
= 0;
1129 struct grub_fshelp_node
*foundnode
;
1131 grub_dl_ref (my_mod
);
1133 data
= grub_udf_mount (file
->device
->disk
);
1137 rootnode
= grub_malloc (get_fshelp_size (data
));
1141 if (grub_udf_read_icb (data
, &data
->root_icb
, rootnode
))
1144 if (grub_fshelp_find_file (name
, rootnode
,
1146 grub_udf_iterate_dir
, grub_udf_read_symlink
,
1150 file
->data
= foundnode
;
1152 file
->size
= U64 (foundnode
->block
.fe
.file_size
);
1154 grub_free (rootnode
);
1159 grub_dl_unref (my_mod
);
1162 grub_free (rootnode
);
1168 grub_udf_read (grub_file_t file
, char *buf
, grub_size_t len
)
1170 struct grub_fshelp_node
*node
= (struct grub_fshelp_node
*) file
->data
;
1172 return grub_udf_read_file (node
, file
->read_hook
, file
->read_hook_data
,
1173 file
->offset
, len
, buf
);
1177 grub_udf_close (grub_file_t file
)
1181 struct grub_fshelp_node
*node
= (struct grub_fshelp_node
*) file
->data
;
1183 grub_free (node
->data
);
1187 grub_dl_unref (my_mod
);
1189 return GRUB_ERR_NONE
;
1193 grub_udf_label (grub_device_t device
, char **label
)
1195 struct grub_udf_data
*data
;
1196 data
= grub_udf_mount (device
->disk
);
1200 *label
= read_string (data
->lvd
.ident
, sizeof (data
->lvd
.ident
), 0);
1209 static struct grub_fs grub_udf_fs
= {
1211 .dir
= grub_udf_dir
,
1212 .open
= grub_udf_open
,
1213 .read
= grub_udf_read
,
1214 .close
= grub_udf_close
,
1215 .label
= grub_udf_label
,
1217 .reserved_first_sector
= 1,
1218 .blocklist_install
= 1,
1225 grub_fs_register (&grub_udf_fs
);
1231 grub_fs_unregister (&grub_udf_fs
);