1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
6 * Libbrasero-media 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 2 of the License, or
9 * (at your option) any later version.
11 * The Libbrasero-media authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-media. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-media is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
19 * Libbrasero-media is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
40 #include <glib/gi18n-lib.h>
42 #include "brasero-units.h"
43 #include "brasero-media.h"
44 #include "brasero-media-private.h"
45 #include "burn-iso9660.h"
46 #include "burn-iso-field.h"
47 #include "burn-susp.h"
48 #include "brasero-media.h"
49 #include "burn-volume.h"
51 struct _BraseroIsoCtx
{
54 gchar buffer
[ISO9660_BLOCK_SIZE
];
69 typedef struct _BraseroIsoCtx BraseroIsoCtx
;
72 BRASERO_ISO_FILE_EXISTENCE
= 1,
73 BRASERO_ISO_FILE_DIRECTORY
= 1 << 1,
74 BRASERO_ISO_FILE_ASSOCIATED
= 1 << 2,
75 BRASERO_ISO_FILE_RECORD
= 1 << 3,
76 BRASERO_ISO_FILE_PROTECTION
= 1 << 4,
78 BRASERO_ISO_FILE_MULTI_EXTENT_FINAL
= 1 << 7
81 struct _BraseroIsoDirRec
{
90 guchar volseq_num
[4];
94 typedef struct _BraseroIsoDirRec BraseroIsoDirRec
;
96 struct _BraseroIsoPrimary
{
103 gchar system_id
[32];
111 guchar volset_size
[4];
112 guchar sequence_num
[4];
113 guchar block_size
[4];
114 guchar path_table_size
[8];
115 guchar L_table_loc
[4];
116 guchar opt_L_table_loc
[4];
117 guchar M_table_loc
[4];
118 guchar opt_M_table_loc
[4];
120 /* the following has a fixed size of 34 bytes */
121 BraseroIsoDirRec root_rec
[0];
123 /* to be continued if needed */
125 typedef struct _BraseroIsoPrimary BraseroIsoPrimary
;
133 #define ISO9660_BYTES_TO_BLOCKS(size) BRASERO_BYTES_TO_SECTORS ((size), ISO9660_BLOCK_SIZE)
136 brasero_iso9660_load_directory_records (BraseroIsoCtx
*ctx
,
137 BraseroVolFile
*parent
,
138 BraseroIsoDirRec
*record
,
141 static BraseroVolFile
*
142 brasero_iso9660_lookup_directory_records (BraseroIsoCtx
*ctx
,
147 brasero_iso9660_is_primary_descriptor (const char *buffer
,
153 vol
= (BraseroVolDesc
*) buffer
;
154 if (memcmp (vol
->id
, "CD001", 5)) {
157 BRASERO_MEDIA_ERROR_IMAGE_INVALID
,
158 _("It does not appear to be a valid ISO image"));
162 /* must be "1" for primary volume */
163 if (vol
->type
!= 1) {
166 BRASERO_MEDIA_ERROR_IMAGE_INVALID
,
167 _("It does not appear to be a valid ISO image"));
175 brasero_iso9660_get_size (const gchar
*block
,
179 BraseroIsoPrimary
*vol
;
181 /* read the size of the volume */
182 vol
= (BraseroIsoPrimary
*) block
;
183 *nb_blocks
= (gint64
) brasero_iso9660_get_733_val (vol
->vol_size
);
189 brasero_iso9660_get_label (const gchar
*block
,
193 BraseroIsoPrimary
*vol
;
195 /* read the identifier */
196 vol
= (BraseroIsoPrimary
*) block
;
197 *label
= g_strndup (vol
->vol_id
, sizeof (vol
->vol_id
));
202 static BraseroIsoResult
203 brasero_iso9660_seek (BraseroIsoCtx
*ctx
, gint address
)
208 /* The size of all the records is given by size member and its location
209 * by its address member. In a set of directory records the first two
210 * records are: '.' (id == 0) and '..' (id == 1). So since we've got
211 * the address of the set load the block. */
212 if (BRASERO_VOL_SRC_SEEK (ctx
->vol
, address
, SEEK_SET
, &(ctx
->error
)) == -1)
213 return BRASERO_ISO_ERROR
;
215 if (!BRASERO_VOL_SRC_READ (ctx
->vol
, ctx
->buffer
, 1, &(ctx
->error
)))
216 return BRASERO_ISO_ERROR
;
218 return BRASERO_ISO_OK
;
221 static BraseroIsoResult
222 brasero_iso9660_next_block (BraseroIsoCtx
*ctx
)
227 if (!BRASERO_VOL_SRC_READ (ctx
->vol
, ctx
->buffer
, 1, &(ctx
->error
)))
228 return BRASERO_ISO_ERROR
;
230 return BRASERO_ISO_OK
;
234 brasero_iso9660_read_susp (BraseroIsoCtx
*ctx
,
235 BraseroSuspCtx
*susp_ctx
,
239 gboolean result
= TRUE
;
240 guint64 current_position
= -1;
242 memset (susp_ctx
, 0, sizeof (BraseroSuspCtx
));
243 if (!brasero_susp_read (susp_ctx
, susp
, susp_len
)) {
244 BRASERO_MEDIA_LOG ("Could not read susp area");
248 while (susp_ctx
->CE_address
) {
249 gchar CE_block
[ISO9660_BLOCK_SIZE
];
254 BRASERO_MEDIA_LOG ("Continuation Area");
256 /* we need to move to another block */
257 seek_res
= BRASERO_VOL_SRC_SEEK (ctx
->vol
, susp_ctx
->CE_address
, SEEK_SET
, NULL
);
258 if (seek_res
== -1) {
259 BRASERO_MEDIA_LOG ("Could not seek to continuation area");
264 if (current_position
== -1)
265 current_position
= seek_res
;
267 if (!BRASERO_VOL_SRC_READ (ctx
->vol
, CE_block
, 1, NULL
)) {
268 BRASERO_MEDIA_LOG ("Could not get continuation area");
273 offset
= susp_ctx
->CE_offset
;
274 len
= MIN (susp_ctx
->CE_len
, sizeof (CE_block
) - offset
);
276 /* reset information about the CE area */
277 memset (&susp_ctx
->CE_address
, 0, sizeof (susp_ctx
->CE_address
));
278 memset (&susp_ctx
->CE_offset
, 0, sizeof (susp_ctx
->CE_offset
));
279 memset (&susp_ctx
->CE_len
, 0, sizeof (susp_ctx
->CE_len
));
281 /* read all information contained in the CE area */
282 if (!brasero_susp_read (susp_ctx
, CE_block
+ offset
, len
)) {
283 BRASERO_MEDIA_LOG ("Could not read continuation area");
289 /* reset the reading address properly */
290 if (current_position
!= -1
291 && BRASERO_VOL_SRC_SEEK (ctx
->vol
, current_position
, SEEK_SET
, NULL
) == -1) {
292 BRASERO_MEDIA_LOG ("Could not rewind to previous position");
300 brasero_iso9660_get_susp (BraseroIsoCtx
*ctx
,
301 BraseroIsoDirRec
*record
,
308 start
= sizeof (BraseroIsoDirRec
) + record
->id_size
;
309 /* padding byte when id_size is an even number */
314 start
+= ctx
->susp_skip
;
316 /* we don't want to go beyond end of buffer */
317 if (start
>= record
->record_size
)
320 len
= record
->record_size
- start
;
328 susp_block
= ((gchar
*) record
) + start
;
330 BRASERO_MEDIA_LOG ("Got susp block");
334 static BraseroIsoResult
335 brasero_iso9660_next_record (BraseroIsoCtx
*ctx
, BraseroIsoDirRec
**retval
)
337 BraseroIsoDirRec
*record
;
339 if (ctx
->offset
> sizeof (ctx
->buffer
)) {
340 BRASERO_MEDIA_LOG ("Invalid record size");
344 if (ctx
->offset
== sizeof (ctx
->buffer
)) {
345 BRASERO_MEDIA_LOG ("No next record");
346 return BRASERO_ISO_END
;
349 /* record_size already checked last time function was called */
350 record
= (BraseroIsoDirRec
*) (ctx
->buffer
+ ctx
->offset
);
351 if (!record
->record_size
) {
352 BRASERO_MEDIA_LOG ("Last record");
353 return BRASERO_ISO_END
;
356 if (record
->record_size
> (sizeof (ctx
->buffer
) - ctx
->offset
)) {
357 gint part_one
, part_two
;
359 /* This is for cross sector boundary records */
360 BRASERO_MEDIA_LOG ("Cross sector boundary record");
362 /* some implementations write across block boundary which is
363 * "forbidden" by ECMA-119. But linux kernel accepts it, so ...
365 /* ctx->error = g_error_new (BRASERO_MEDIA_ERROR,
366 BRASERO_MEDIA_ERROR_IMAGE_INVALID,
367 _("It does not appear to be a valid ISO image"));
370 if (ctx
->spare_record
)
371 g_free (ctx
->spare_record
);
373 ctx
->spare_record
= g_new0 (gchar
, record
->record_size
);
375 part_one
= sizeof (ctx
->buffer
) - ctx
->offset
;
376 part_two
= record
->record_size
- part_one
;
378 memcpy (ctx
->spare_record
,
379 ctx
->buffer
+ ctx
->offset
,
382 if (brasero_iso9660_next_block (ctx
) == BRASERO_ISO_ERROR
)
385 memcpy (ctx
->spare_record
+ part_one
,
388 ctx
->offset
= part_two
;
390 record
= (BraseroIsoDirRec
*) ctx
->spare_record
;
393 ctx
->offset
+= record
->record_size
;
396 return BRASERO_ISO_OK
;
400 ctx
->error
= g_error_new (BRASERO_MEDIA_ERROR
,
401 BRASERO_MEDIA_ERROR_IMAGE_INVALID
,
402 _("It does not appear to be a valid ISO image"));
403 return BRASERO_ISO_ERROR
;
406 static BraseroIsoResult
407 brasero_iso9660_get_first_directory_record (BraseroIsoCtx
*ctx
,
408 BraseroIsoDirRec
**record
,
411 BraseroIsoResult result
;
413 BRASERO_MEDIA_LOG ("Reading directory record");
415 result
= brasero_iso9660_seek (ctx
, address
);
416 if (result
!= BRASERO_ISO_OK
)
417 return BRASERO_ISO_ERROR
;
420 result
= brasero_iso9660_next_record (ctx
, record
);
421 if (result
!= BRASERO_ISO_OK
)
422 return BRASERO_ISO_ERROR
;
424 return BRASERO_ISO_OK
;
427 static BraseroVolFile
*
428 brasero_iso9660_read_file_record (BraseroIsoCtx
*ctx
,
429 BraseroIsoDirRec
*record
,
430 BraseroSuspCtx
*susp_ctx
)
432 BraseroVolFile
*file
;
433 BraseroVolFileExtent
*extent
;
435 if (record
->id_size
> record
->record_size
- sizeof (BraseroIsoDirRec
)) {
436 BRASERO_MEDIA_LOG ("Filename is too long");
437 ctx
->error
= g_error_new (BRASERO_MEDIA_ERROR
,
438 BRASERO_MEDIA_ERROR_IMAGE_INVALID
,
439 _("It does not appear to be a valid ISO image"));
443 file
= g_new0 (BraseroVolFile
, 1);
445 file
->name
= g_new0 (gchar
, record
->id_size
+ 1);
446 memcpy (file
->name
, record
->id
, record
->id_size
);
448 file
->specific
.file
.size_bytes
= brasero_iso9660_get_733_val (record
->file_size
);
450 /* NOTE: a file can be in multiple places */
451 extent
= g_new (BraseroVolFileExtent
, 1);
452 extent
->block
= brasero_iso9660_get_733_val (record
->address
);
453 extent
->size
= brasero_iso9660_get_733_val (record
->file_size
);
454 file
->specific
.file
.extents
= g_slist_prepend (file
->specific
.file
.extents
, extent
);
456 /* see if we've got a susp area */
458 BRASERO_MEDIA_LOG ("New file %s", file
->name
);
462 BRASERO_MEDIA_LOG ("New file %s with a suspend area", file
->name
);
464 if (susp_ctx
->rr_name
) {
465 BRASERO_MEDIA_LOG ("Got a susp (RR) %s", susp_ctx
->rr_name
);
466 file
->rr_name
= susp_ctx
->rr_name
;
467 susp_ctx
->rr_name
= NULL
;
473 static BraseroVolFile
*
474 brasero_iso9660_read_directory_record (BraseroIsoCtx
*ctx
,
475 BraseroIsoDirRec
*record
,
481 BraseroSuspCtx susp_ctx
;
482 BraseroVolFile
*directory
;
484 if (record
->id_size
> record
->record_size
- sizeof (BraseroIsoDirRec
)) {
485 BRASERO_MEDIA_LOG ("Filename is too long");
486 ctx
->error
= g_error_new (BRASERO_MEDIA_ERROR
,
487 BRASERO_MEDIA_ERROR_IMAGE_INVALID
,
488 _("It does not appear to be a valid ISO image"));
492 /* create the directory and set information */
493 directory
= g_new0 (BraseroVolFile
, 1);
494 directory
->isdir
= TRUE
;
495 directory
->isdir_loaded
= FALSE
;
496 directory
->name
= g_new0 (gchar
, record
->id_size
+ 1);
497 memcpy (directory
->name
, record
->id
, record
->id_size
);
499 if (ctx
->has_susp
&& ctx
->has_RR
) {
500 /* See if we've got a susp area. Do it now to see if it has a CL
501 * entry. The rest will be checked later after reading contents.
503 susp
= brasero_iso9660_get_susp (ctx
, record
, &susp_len
);
504 if (!brasero_iso9660_read_susp (ctx
, &susp_ctx
, susp
, susp_len
)) {
505 BRASERO_MEDIA_LOG ("Could not read susp area");
506 brasero_volume_file_free (directory
);
510 /* look for a "CL" SUSP entry in case the directory was relocated */
511 if (susp_ctx
.CL_address
) {
512 BRASERO_MEDIA_LOG ("Entry has a CL entry");
513 address
= susp_ctx
.CL_address
;
516 address
= brasero_iso9660_get_733_val (record
->address
);
518 BRASERO_MEDIA_LOG ("New directory %s with susp area", directory
->name
);
520 /* if this directory has a "RE" susp entry then drop it; it's
521 * not at the right place in the Rock Ridge file hierarchy. It
522 * will probably be skipped */
523 if (susp_ctx
.has_RE
) {
524 BRASERO_MEDIA_LOG ("Rock Ridge relocated directory. Skipping entry.");
525 directory
->relocated
= TRUE
;
528 if (susp_ctx
.rr_name
) {
529 BRASERO_MEDIA_LOG ("Got a susp (RR) %s", susp_ctx
.rr_name
);
530 directory
->rr_name
= susp_ctx
.rr_name
;
531 susp_ctx
.rr_name
= NULL
;
534 brasero_susp_ctx_clean (&susp_ctx
);
537 address
= brasero_iso9660_get_733_val (record
->address
);
539 /* load contents if recursive */
543 brasero_iso9660_get_first_directory_record (ctx
,
546 children
= brasero_iso9660_load_directory_records (ctx
,
550 if (!children
&& ctx
->error
) {
551 brasero_volume_file_free (directory
);
552 if (ctx
->has_susp
&& ctx
->has_RR
)
553 brasero_susp_ctx_clean (&susp_ctx
);
558 directory
->isdir_loaded
= TRUE
;
559 directory
->specific
.dir
.children
= children
;
561 else /* store the address of contents for later use */
562 directory
->specific
.dir
.address
= address
;
564 BRASERO_MEDIA_LOG ("New directory %s", directory
->name
);
569 brasero_iso9660_load_directory_records (BraseroIsoCtx
*ctx
,
570 BraseroVolFile
*parent
,
571 BraseroIsoDirRec
*record
,
576 gint max_record_size
;
577 BraseroVolFile
*entry
;
578 GList
*children
= NULL
;
579 BraseroIsoResult result
;
580 GSList
*directories
= NULL
;
582 max_record_size
= brasero_iso9660_get_733_val (record
->file_size
);
583 max_block
= ISO9660_BYTES_TO_BLOCKS (max_record_size
);
584 BRASERO_MEDIA_LOG ("Maximum directory record length %i block (= %i bytes)", max_block
, max_record_size
);
587 result
= brasero_iso9660_next_record (ctx
, &record
);
588 if (result
!= BRASERO_ISO_OK
)
591 BRASERO_MEDIA_LOG ("Skipped '.' and '..'");
594 BraseroIsoResult result
;
596 result
= brasero_iso9660_next_record (ctx
, &record
);
597 if (result
== BRASERO_ISO_END
) {
598 if (ctx
->num_blocks
>= max_block
)
601 result
= brasero_iso9660_next_block (ctx
);
602 if (result
!= BRASERO_ISO_OK
)
607 else if (result
== BRASERO_ISO_ERROR
)
613 /* if it's a directory, keep the record for later (we don't
614 * want to change the reading offset for the moment) */
615 if (record
->flags
& BRASERO_ISO_FILE_DIRECTORY
) {
618 copy
= g_new0 (gchar
, record
->record_size
);
619 memcpy (copy
, record
, record
->record_size
);
620 directories
= g_slist_prepend (directories
, copy
);
625 BraseroSuspCtx susp_ctx
= { NULL
, };
629 /* See if we've got a susp area. Do it now to see if it
630 * has a CL entry. The rest will be checked later after
631 * reading contents. Otherwise we wouldn't be able to
632 * get deep directories that are flagged as files. */
633 susp
= brasero_iso9660_get_susp (ctx
, record
, &susp_len
);
634 if (!brasero_iso9660_read_susp (ctx
, &susp_ctx
, susp
, susp_len
)) {
635 BRASERO_MEDIA_LOG ("Could not read susp area");
639 /* look for a "CL" SUSP entry in case the directory was
640 * relocated. If it has, it's a directory and keep it
642 if (susp_ctx
.CL_address
) {
645 BRASERO_MEDIA_LOG ("Entry has a CL entry, keeping for later");
646 copy
= g_new0 (gchar
, record
->record_size
);
647 memcpy (copy
, record
, record
->record_size
);
648 directories
= g_slist_prepend (directories
, copy
);
650 brasero_susp_ctx_clean (&susp_ctx
);
651 memset (&susp_ctx
, 0, sizeof (BraseroSuspCtx
));
655 entry
= brasero_iso9660_read_file_record (ctx
, record
, &susp_ctx
);
656 brasero_susp_ctx_clean (&susp_ctx
);
659 entry
= brasero_iso9660_read_file_record (ctx
, record
, NULL
);
664 entry
->parent
= parent
;
666 /* check that we don't have another file record for the
667 * same file (usually files > 4G). It always follows
670 BraseroVolFile
*last
;
672 last
= children
->data
;
673 if (!last
->isdir
&& !strcmp (BRASERO_VOLUME_FILE_NAME (last
), BRASERO_VOLUME_FILE_NAME (entry
))) {
674 /* add size and addresses */
675 ctx
->data_blocks
+= ISO9660_BYTES_TO_BLOCKS (entry
->specific
.file
.size_bytes
);
676 last
= brasero_volume_file_merge (last
, entry
);
677 BRASERO_MEDIA_LOG ("Multi extent file");
682 children
= g_list_prepend (children
, entry
);
683 ctx
->data_blocks
+= ISO9660_BYTES_TO_BLOCKS (entry
->specific
.file
.size_bytes
);
686 /* Takes care of the directories: we accumulate them not to change the
687 * offset of file descriptor FILE */
688 for (iter
= directories
; iter
; iter
= iter
->next
) {
691 entry
= brasero_iso9660_read_directory_record (ctx
, record
, recursive
);
695 if (entry
->relocated
) {
696 brasero_volume_file_free (entry
);
700 entry
->parent
= parent
;
701 children
= g_list_prepend (children
, entry
);
703 g_slist_foreach (directories
, (GFunc
) g_free
, NULL
);
704 g_slist_free (directories
);
710 g_list_foreach (children
, (GFunc
) brasero_volume_file_free
, NULL
);
711 g_list_free (children
);
713 g_slist_foreach (directories
, (GFunc
) g_free
, NULL
);
714 g_slist_free (directories
);
720 brasero_iso9660_check_SUSP_RR_use (BraseroIsoCtx
*ctx
,
721 BraseroIsoDirRec
*record
)
723 BraseroSuspCtx susp_ctx
;
727 susp
= brasero_iso9660_get_susp (ctx
, record
, &susp_len
);
728 brasero_iso9660_read_susp (ctx
, &susp_ctx
, susp
, susp_len
);
730 ctx
->has_susp
= susp_ctx
.has_SP
;
731 ctx
->has_RR
= susp_ctx
.has_RockRidge
;
732 ctx
->susp_skip
= susp_ctx
.skip
;
733 ctx
->is_root
= FALSE
;
736 BRASERO_MEDIA_LOG ("File system supports system use sharing protocol");
739 BRASERO_MEDIA_LOG ("File system has Rock Ridge extension");
741 brasero_susp_ctx_clean (&susp_ctx
);
746 brasero_iso9660_ctx_init (BraseroIsoCtx
*ctx
, BraseroVolSrc
*vol
)
748 memset (ctx
, 0, sizeof (BraseroIsoCtx
));
754 /* to fully initialize the context we need the root directory record */
758 brasero_iso9660_get_contents (BraseroVolSrc
*vol
,
763 BraseroIsoPrimary
*primary
;
764 BraseroIsoDirRec
*record
;
765 BraseroVolFile
*volfile
;
766 BraseroIsoDirRec
*root
;
771 primary
= (BraseroIsoPrimary
*) block
;
772 root
= primary
->root_rec
;
775 address
= brasero_iso9660_get_733_val (root
->address
);
776 brasero_iso9660_ctx_init (&ctx
, vol
);
777 brasero_iso9660_get_first_directory_record (&ctx
, &record
, address
);
778 brasero_iso9660_check_SUSP_RR_use (&ctx
, record
);
780 /* create volume file */
781 volfile
= g_new0 (BraseroVolFile
, 1);
782 volfile
->isdir
= TRUE
;
783 volfile
->isdir_loaded
= FALSE
;
785 children
= brasero_iso9660_load_directory_records (&ctx
,
789 volfile
->specific
.dir
.children
= children
;
791 if (ctx
.spare_record
)
792 g_free (ctx
.spare_record
);
795 *data_blocks
= ctx
.data_blocks
;
797 if (!children
&& ctx
.error
) {
799 g_propagate_error (error
, ctx
.error
);
801 brasero_volume_file_free (volfile
);
808 static BraseroVolFile
*
809 brasero_iso9660_lookup_directory_record_RR (BraseroIsoCtx
*ctx
,
812 BraseroIsoDirRec
*record
)
814 BraseroVolFile
*entry
= NULL
;
815 BraseroSuspCtx susp_ctx
;
816 gchar record_name
[256];
820 /* See if we've got a susp area. Do it now to see if it
821 * has a CL entry and rr_name. */
822 susp
= brasero_iso9660_get_susp (ctx
, record
, &susp_len
);
823 if (!brasero_iso9660_read_susp (ctx
, &susp_ctx
, susp
, susp_len
)) {
824 BRASERO_MEDIA_LOG ("Could not read susp area");
829 if (!susp_ctx
.rr_name
) {
830 memcpy (record_name
, record
->id
, record
->id_size
);
831 record_name
[record
->id_size
] = '\0';
834 strcpy (record_name
, susp_ctx
.rr_name
);
836 if (!(record
->flags
& BRASERO_ISO_FILE_DIRECTORY
)) {
838 /* Look for a "CL" SUSP entry in case it was
839 * relocated. If it has, it's a directory. */
840 if (susp_ctx
.CL_address
&& !strncmp (record_name
, path
, len
)) {
841 /* move path forward */
845 entry
= brasero_iso9660_lookup_directory_records (ctx
,
847 susp_ctx
.CL_address
);
850 else if (!strcmp (record_name
, path
))
851 entry
= brasero_iso9660_read_file_record (ctx
,
855 else if (len
&& !strncmp (record_name
, path
, len
)) {
858 /* move path forward */
862 address
= brasero_iso9660_get_733_val (record
->address
);
863 entry
= brasero_iso9660_lookup_directory_records (ctx
,
868 brasero_susp_ctx_clean (&susp_ctx
);
872 static BraseroVolFile
*
873 brasero_iso9660_lookup_directory_record_ISO (BraseroIsoCtx
*ctx
,
876 BraseroIsoDirRec
*record
)
878 BraseroVolFile
*entry
= NULL
;
880 if (!(record
->flags
& BRASERO_ISO_FILE_DIRECTORY
)) {
881 if (!len
&& !strncmp (record
->id
, path
, record
->id_size
))
882 entry
= brasero_iso9660_read_file_record (ctx
,
886 else if (len
&& !strncmp (record
->id
, path
, record
->id_size
)) {
889 /* move path forward */
893 address
= brasero_iso9660_get_733_val (record
->address
);
894 entry
= brasero_iso9660_lookup_directory_records (ctx
,
902 static BraseroVolFile
*
903 brasero_iso9660_lookup_directory_records (BraseroIsoCtx
*ctx
,
910 gint max_record_size
;
911 BraseroIsoResult result
;
912 BraseroIsoDirRec
*record
;
913 BraseroVolFile
*file
= NULL
;
915 BRASERO_MEDIA_LOG ("Reading directory record");
917 result
= brasero_iso9660_seek (ctx
, address
);
918 if (result
!= BRASERO_ISO_OK
)
922 result
= brasero_iso9660_next_record (ctx
, &record
);
923 if (result
!= BRASERO_ISO_OK
)
926 /* Look for "SP" SUSP if it's root directory. Also look for "ER" which
927 * should tell us whether Rock Ridge could be used. */
929 BraseroSuspCtx susp_ctx
;
933 susp
= brasero_iso9660_get_susp (ctx
, record
, &susp_len
);
934 brasero_iso9660_read_susp (ctx
, &susp_ctx
, susp
, susp_len
);
936 ctx
->has_susp
= susp_ctx
.has_SP
;
937 ctx
->has_RR
= susp_ctx
.has_RockRidge
;
938 ctx
->susp_skip
= susp_ctx
.skip
;
939 ctx
->is_root
= FALSE
;
941 brasero_susp_ctx_clean (&susp_ctx
);
944 BRASERO_MEDIA_LOG ("File system supports system use sharing protocol");
947 BRASERO_MEDIA_LOG ("File system has Rock Ridge extension");
950 max_record_size
= brasero_iso9660_get_733_val (record
->file_size
);
951 max_block
= ISO9660_BYTES_TO_BLOCKS (max_record_size
);
952 BRASERO_MEDIA_LOG ("Maximum directory record length %i block (= %i bytes)", max_block
, max_record_size
);
955 result
= brasero_iso9660_next_record (ctx
, &record
);
956 if (result
!= BRASERO_ISO_OK
)
959 BRASERO_MEDIA_LOG ("Skipped '.' and '..'");
961 end
= strchr (path
, '/');
963 /* reached the final file */
969 BraseroIsoResult result
;
970 BraseroVolFile
*entry
;
972 result
= brasero_iso9660_next_record (ctx
, &record
);
973 if (result
== BRASERO_ISO_END
) {
974 if (ctx
->num_blocks
>= max_block
) {
975 BRASERO_MEDIA_LOG ("Reached the end of directory record");
979 result
= brasero_iso9660_next_block (ctx
);
980 if (result
!= BRASERO_ISO_OK
) {
981 BRASERO_MEDIA_LOG ("Failed to load next block");
987 else if (result
== BRASERO_ISO_ERROR
) {
988 BRASERO_MEDIA_LOG ("Error retrieving next record");
993 BRASERO_MEDIA_LOG ("No record !!!");
998 entry
= brasero_iso9660_lookup_directory_record_RR (ctx
,
1003 entry
= brasero_iso9660_lookup_directory_record_ISO (ctx
,
1012 /* add size and addresses */
1013 file
= brasero_volume_file_merge (file
, entry
);
1014 BRASERO_MEDIA_LOG ("Multi extent file");
1019 /* carry on in case that's a multi extent file */
1026 brasero_iso9660_get_file (BraseroVolSrc
*vol
,
1031 BraseroIsoPrimary
*primary
;
1032 BraseroIsoDirRec
*root
;
1033 BraseroVolFile
*entry
;
1037 primary
= (BraseroIsoPrimary
*) block
;
1038 root
= primary
->root_rec
;
1040 address
= brasero_iso9660_get_733_val (root
->address
);
1041 brasero_iso9660_ctx_init (&ctx
, vol
);
1043 /* now that we have root block address, skip first "/" and go. */
1045 entry
= brasero_iso9660_lookup_directory_records (&ctx
,
1050 if (ctx
.spare_record
)
1051 g_free (ctx
.spare_record
);
1053 if (error
&& ctx
.error
)
1054 g_propagate_error (error
, ctx
.error
);
1060 brasero_iso9660_get_directory_contents (BraseroVolSrc
*vol
,
1061 const gchar
*vol_desc
,
1065 BraseroIsoDirRec
*record
= NULL
;
1066 BraseroIsoPrimary
*primary
;
1067 BraseroIsoDirRec
*root
;
1071 /* Check root "." for use of RR and things like that */
1072 primary
= (BraseroIsoPrimary
*) vol_desc
;
1073 root
= primary
->root_rec
;
1075 brasero_iso9660_ctx_init (&ctx
, vol
);
1076 brasero_iso9660_get_first_directory_record (&ctx
,
1078 brasero_iso9660_get_733_val (root
->address
));
1079 brasero_iso9660_check_SUSP_RR_use (&ctx
, record
);
1081 /* Seek up to the contents of the directory */
1083 brasero_iso9660_get_first_directory_record (&ctx
,
1088 children
= brasero_iso9660_load_directory_records (&ctx
,
1092 if (ctx
.error
&& error
)
1093 g_propagate_error (error
, ctx
.error
);