2 * Copyright (c) 2003-2004 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_iso9660.c,v 1.13 2006/03/21 16:55:46 kientzle Exp $");
33 /* #include <stdint.h> */ /* See archive_platform.h */
41 #include "archive_entry.h"
42 #include "archive_private.h"
43 #include "archive_string.h"
46 * An overview of ISO 9660 format:
48 * Each disk is laid out as follows:
49 * * 32k reserved for private use
50 * * Volume descriptor table. Each volume descriptor
51 * is 2k and specifies basic format information.
52 * The "Primary Volume Descriptor" (PVD) is defined by the
53 * standard and should always be present; other volume
54 * descriptors include various vendor-specific extensions.
55 * * Files and directories. Each file/dir is specified by
56 * an "extent" (starting sector and length in bytes).
57 * Dirs are just files with directory records packed one
58 * after another. The PVD contains a single dir entry
59 * specifying the location of the root directory. Everything
60 * else follows from there.
62 * This module works by first reading the volume descriptors, then
63 * building a list of directory entries, sorted by starting
64 * sector. At each step, I look for the earliest dir entry that
65 * hasn't yet been read, seek forward to that location and read
66 * that entry. If it's a dir, I slurp in the new dir entries and
67 * add them to the heap; if it's a regular file, I return the
68 * corresponding archive_entry and wait for the client to request
69 * the file body. This strategy allows us to read most compliant
70 * CDs with a single pass through the data, as required by libarchive.
73 /* Structure of on-disk PVD. */
74 struct iso9660_primary_volume_descriptor
{
75 unsigned char type
[1];
77 unsigned char version
[1];
82 char volume_space_size
[8];
84 char volume_set_size
[4];
85 char volume_sequence_number
[4];
86 char logical_block_size
[4];
87 char path_table_size
[8];
88 char type_1_path_table
[4];
89 char opt_type_1_path_table
[4];
90 char type_m_path_table
[4];
91 char opt_type_m_path_table
[4];
92 char root_directory_record
[34];
93 char volume_set_id
[128];
94 char publisher_id
[128];
95 char preparer_id
[128];
96 char application_id
[128];
97 char copyright_file_id
[37];
98 char abstract_file_id
[37];
99 char bibliographic_file_id
[37];
100 char creation_date
[17];
101 char modification_date
[17];
102 char expiration_date
[17];
103 char effective_date
[17];
104 char file_structure_version
[1];
106 char application_data
[512];
109 /* Structure of an on-disk directory record. */
110 struct iso9660_directory_record
{
111 unsigned char length
[1];
112 unsigned char ext_attr_length
[1];
113 unsigned char extent
[8];
114 unsigned char size
[8];
116 unsigned char flags
[1];
117 unsigned char file_unit_size
[1];
118 unsigned char interleave
[1];
119 unsigned char volume_sequence_number
[4];
120 unsigned char name_len
[1];
128 /* In-memory storage for a directory record. */
130 struct file_info
*parent
;
132 uint64_t offset
; /* Offset on disk. */
133 uint64_t size
; /* File size in bytes. */
134 uint64_t ce_offset
; /* Offset of CE */
135 uint64_t ce_size
; /* Size of CE */
136 time_t mtime
; /* File last modified time. */
137 time_t atime
; /* File last accessed time. */
138 time_t ctime
; /* File creation time. */
144 char *name
; /* Null-terminated filename. */
145 struct archive_string symlink
;
151 #define ISO9660_MAGIC 0x96609660
152 int bid
; /* If non-zero, return this as our bid. */
153 struct archive_string pathname
;
154 char seenRockridge
; /* Set true if RR extensions are used. */
155 unsigned char suspOffset
;
157 uint64_t previous_offset
;
158 uint64_t previous_size
;
159 struct archive_string previous_pathname
;
161 /* TODO: Make this a heap for fast inserts and deletions. */
162 struct file_info
**pending_files
;
163 int pending_files_allocated
;
164 int pending_files_used
;
166 uint64_t current_position
;
167 ssize_t logical_block_size
;
169 off_t entry_sparse_offset
;
170 ssize_t entry_bytes_remaining
;
173 static void add_entry(struct iso9660
*iso9660
, struct file_info
*file
);
174 static int archive_read_format_iso9660_bid(struct archive
*);
175 static int archive_read_format_iso9660_cleanup(struct archive
*);
176 static int archive_read_format_iso9660_read_data(struct archive
*,
177 const void **, size_t *, off_t
*);
178 static int archive_read_format_iso9660_read_header(struct archive
*,
179 struct archive_entry
*);
180 static const char *build_pathname(struct archive_string
*, struct file_info
*);
181 static void dump_isodirrec(FILE *, const struct iso9660_directory_record
*);
182 static time_t time_from_tm(struct tm
*);
183 static time_t isodate17(const void *);
184 static time_t isodate7(const void *);
185 static int isPVD(struct iso9660
*, const char *);
186 static struct file_info
*next_entry(struct iso9660
*);
187 static int next_entry_seek(struct archive
*a
, struct iso9660
*iso9660
,
188 struct file_info
**pfile
);
189 static struct file_info
*
190 parse_file_info(struct iso9660
*iso9660
,
191 struct file_info
*parent
,
192 const struct iso9660_directory_record
*isodirrec
);
193 static void parse_rockridge(struct iso9660
*iso9660
,
194 struct file_info
*file
, const unsigned char *start
,
195 const unsigned char *end
);
196 static void release_file(struct iso9660
*, struct file_info
*);
197 static int toi(const void *p
, int n
);
200 archive_read_support_format_iso9660(struct archive
*a
)
202 struct iso9660
*iso9660
;
205 iso9660
= malloc(sizeof(*iso9660
));
206 if (iso9660
== NULL
) {
207 archive_set_error(a
, ENOMEM
, "Can't allocate iso9660 data");
208 return (ARCHIVE_FATAL
);
210 memset(iso9660
, 0, sizeof(*iso9660
));
211 iso9660
->magic
= ISO9660_MAGIC
;
212 iso9660
->bid
= -1; /* We haven't yet bid. */
214 r
= __archive_read_register_format(a
,
216 archive_read_format_iso9660_bid
,
217 archive_read_format_iso9660_read_header
,
218 archive_read_format_iso9660_read_data
,
220 archive_read_format_iso9660_cleanup
);
222 if (r
!= ARCHIVE_OK
) {
231 archive_read_format_iso9660_bid(struct archive
*a
)
233 struct iso9660
*iso9660
;
238 iso9660
= *(a
->pformat_data
);
240 if (iso9660
->bid
>= 0)
241 return (iso9660
->bid
);
244 * Skip the first 32k (reserved area) and get the first
245 * 8 sectors of the volume descriptor table. Of course,
246 * if the I/O layer gives us more, we'll take it.
248 bytes_read
= (a
->compression_read_ahead
)(a
, &h
, 32768 + 8*2048);
249 if (bytes_read
< 32768 + 8*2048)
250 return (iso9660
->bid
= -1);
253 /* Skip the reserved area. */
257 /* Check each volume descriptor to locate the PVD. */
258 for (; bytes_read
> 2048; bytes_read
-= 2048, p
+= 2048) {
259 iso9660
->bid
= isPVD(iso9660
, p
);
260 if (iso9660
->bid
> 0)
261 return (iso9660
->bid
);
262 if (*p
== '\xff') /* End-of-volume-descriptor marker. */
266 /* We didn't find a valid PVD; return a bid of zero. */
268 return (iso9660
->bid
);
272 isPVD(struct iso9660
*iso9660
, const char *h
)
274 const struct iso9660_primary_volume_descriptor
*voldesc
;
275 struct file_info
*file
;
279 if (memcmp(h
+1, "CD001", 5) != 0)
283 voldesc
= (const struct iso9660_primary_volume_descriptor
*)h
;
284 iso9660
->logical_block_size
= toi(&voldesc
->logical_block_size
, 2);
286 /* Store the root directory in the pending list. */
287 file
= parse_file_info(iso9660
, NULL
,
288 (struct iso9660_directory_record
*)&voldesc
->root_directory_record
);
289 add_entry(iso9660
, file
);
294 archive_read_format_iso9660_read_header(struct archive
*a
,
295 struct archive_entry
*entry
)
298 struct iso9660
*iso9660
;
299 struct file_info
*file
;
303 iso9660
= *(a
->pformat_data
);
305 if (!a
->archive_format
) {
306 a
->archive_format
= ARCHIVE_FORMAT_ISO9660
;
307 a
->archive_format_name
= "ISO9660";
310 /* Get the next entry that appears after the current offset. */
311 r
= next_entry_seek(a
, iso9660
, &file
);
315 iso9660
->entry_bytes_remaining
= file
->size
;
316 iso9660
->entry_sparse_offset
= 0; /* Offset for sparse-file-aware clients. */
318 /* Set up the entry structure with information about this entry. */
319 memset(&st
, 0, sizeof(st
));
320 st
.st_mode
= file
->mode
;
321 st
.st_uid
= file
->uid
;
322 st
.st_gid
= file
->gid
;
323 st
.st_nlink
= file
->nlinks
;
324 st
.st_ino
= file
->inode
;
325 st
.st_mtime
= file
->mtime
;
326 st
.st_ctime
= file
->ctime
;
327 st
.st_atime
= file
->atime
;
328 st
.st_size
= iso9660
->entry_bytes_remaining
;
329 archive_entry_copy_stat(entry
, &st
);
330 archive_string_empty(&iso9660
->pathname
);
331 archive_entry_set_pathname(entry
,
332 build_pathname(&iso9660
->pathname
, file
));
333 if (file
->symlink
.s
!= NULL
)
334 archive_entry_set_symlink(entry
, file
->symlink
.s
);
336 /* If this entry points to the same data as the previous
337 * entry, convert this into a hardlink to that entry.
338 * But don't bother for zero-length files. */
339 if (file
->offset
== iso9660
->previous_offset
340 && file
->size
== iso9660
->previous_size
342 archive_entry_set_hardlink(entry
,
343 iso9660
->previous_pathname
.s
);
344 iso9660
->entry_bytes_remaining
= 0;
345 iso9660
->entry_sparse_offset
= 0;
346 release_file(iso9660
, file
);
350 /* If the offset is before our current position, we can't
351 * seek backwards to extract it, so issue a warning. */
352 if (file
->offset
< iso9660
->current_position
) {
353 archive_set_error(a
, ARCHIVE_ERRNO_MISC
,
354 "Ignoring out-of-order file");
355 iso9660
->entry_bytes_remaining
= 0;
356 iso9660
->entry_sparse_offset
= 0;
357 release_file(iso9660
, file
);
358 return (ARCHIVE_WARN
);
361 iso9660
->previous_size
= file
->size
;
362 iso9660
->previous_offset
= file
->offset
;
363 archive_strcpy(&iso9660
->previous_pathname
, iso9660
->pathname
.s
);
365 /* If this is a directory, read in all of the entries right now. */
366 if (S_ISDIR(st
.st_mode
)) {
367 while (iso9660
->entry_bytes_remaining
> 0) {
369 const unsigned char *p
;
370 ssize_t step
= iso9660
->logical_block_size
;
371 if (step
> iso9660
->entry_bytes_remaining
)
372 step
= iso9660
->entry_bytes_remaining
;
373 bytes_read
= (a
->compression_read_ahead
)(a
, &block
, step
);
374 if (bytes_read
< step
) {
375 archive_set_error(a
, ARCHIVE_ERRNO_MISC
,
376 "Failed to read full block when scanning ISO9660 directory list");
377 release_file(iso9660
, file
);
378 return (ARCHIVE_FATAL
);
380 if (bytes_read
> step
)
382 (a
->compression_read_consume
)(a
, bytes_read
);
383 iso9660
->current_position
+= bytes_read
;
384 iso9660
->entry_bytes_remaining
-= bytes_read
;
386 *p
!= 0 && p
< (const unsigned char *)block
+ bytes_read
;
388 const struct iso9660_directory_record
*dr
389 = (const struct iso9660_directory_record
*)p
;
390 struct file_info
*child
;
392 /* Skip '.' entry. */
393 if (dr
->name_len
[0] == 1
394 && dr
->name
[0] == '\0')
396 /* Skip '..' entry. */
397 if (dr
->name_len
[0] == 1
398 && dr
->name
[0] == '\001')
400 child
= parse_file_info(iso9660
, file
, dr
);
401 add_entry(iso9660
, child
);
402 if (iso9660
->seenRockridge
) {
404 ARCHIVE_FORMAT_ISO9660_ROCKRIDGE
;
405 a
->archive_format_name
=
406 "ISO9660 with Rockridge extensions";
412 release_file(iso9660
, file
);
417 archive_read_format_iso9660_read_data(struct archive
*a
,
418 const void **buff
, size_t *size
, off_t
*offset
)
421 struct iso9660
*iso9660
;
423 iso9660
= *(a
->pformat_data
);
424 if (iso9660
->entry_bytes_remaining
<= 0) {
427 *offset
= iso9660
->entry_sparse_offset
;
428 return (ARCHIVE_EOF
);
431 bytes_read
= (a
->compression_read_ahead
)(a
, buff
, 1);
433 archive_set_error(a
, ARCHIVE_ERRNO_MISC
,
434 "Truncated input file");
436 return (ARCHIVE_FATAL
);
437 if (bytes_read
> iso9660
->entry_bytes_remaining
)
438 bytes_read
= iso9660
->entry_bytes_remaining
;
440 *offset
= iso9660
->entry_sparse_offset
;
441 iso9660
->entry_sparse_offset
+= bytes_read
;
442 iso9660
->entry_bytes_remaining
-= bytes_read
;
443 iso9660
->current_position
+= bytes_read
;
444 (a
->compression_read_consume
)(a
, bytes_read
);
449 archive_read_format_iso9660_cleanup(struct archive
*a
)
451 struct iso9660
*iso9660
;
452 struct file_info
*file
;
454 iso9660
= *(a
->pformat_data
);
455 while ((file
= next_entry(iso9660
)) != NULL
)
456 release_file(iso9660
, file
);
457 archive_string_free(&iso9660
->pathname
);
458 archive_string_free(&iso9660
->previous_pathname
);
460 *(a
->pformat_data
) = NULL
;
465 * This routine parses a single ISO directory record, makes sense
466 * of any extensions, and stores the result in memory.
468 static struct file_info
*
469 parse_file_info(struct iso9660
*iso9660
, struct file_info
*parent
,
470 const struct iso9660_directory_record
*isodirrec
)
472 struct file_info
*file
;
474 /* TODO: Sanity check that name_len doesn't exceed length, etc. */
476 /* Create a new file entry and copy data from the ISO dir record. */
477 file
= malloc(sizeof(*file
));
480 memset(file
, 0, sizeof(*file
));
481 file
->parent
= parent
;
484 file
->offset
= toi(isodirrec
->extent
, 4)
485 * iso9660
->logical_block_size
;
486 file
->size
= toi(isodirrec
->size
, 4);
487 file
->mtime
= isodate7(isodirrec
->date
);
488 file
->ctime
= file
->atime
= file
->mtime
;
489 file
->name
= malloc(isodirrec
->name_len
[0] + 1);
490 if (file
->name
== NULL
) {
494 memcpy(file
->name
, isodirrec
->name
, isodirrec
->name_len
[0]);
495 file
->name
[(int)isodirrec
->name_len
[0]] = '\0';
496 if (isodirrec
->flags
[0] & 0x02)
497 file
->mode
= S_IFDIR
| 0700;
499 file
->mode
= S_IFREG
| 0400;
501 /* Rockridge extensions overwrite information from above. */
503 const unsigned char *rr_start
, *rr_end
;
504 rr_end
= (const unsigned char *)isodirrec
505 + isodirrec
->length
[0];
506 rr_start
= (const unsigned char *)isodirrec
->name
507 + isodirrec
->name_len
[0];
508 if ((isodirrec
->name_len
[0] & 1) == 0)
510 rr_start
+= iso9660
->suspOffset
;
511 parse_rockridge(iso9660
, file
, rr_start
, rr_end
);
514 /* DEBUGGING: Warn about attributes I don't yet fully support. */
515 if ((isodirrec
->flags
[0] & ~0x02) != 0) {
516 fprintf(stderr
, "\n ** Unrecognized flag: ");
517 dump_isodirrec(stderr
, isodirrec
);
518 fprintf(stderr
, "\n");
519 } else if (toi(isodirrec
->volume_sequence_number
, 2) != 1) {
520 fprintf(stderr
, "\n ** Unrecognized sequence number: ");
521 dump_isodirrec(stderr
, isodirrec
);
522 fprintf(stderr
, "\n");
523 } else if (isodirrec
->file_unit_size
[0] != 0) {
524 fprintf(stderr
, "\n ** Unexpected file unit size: ");
525 dump_isodirrec(stderr
, isodirrec
);
526 fprintf(stderr
, "\n");
527 } else if (isodirrec
->interleave
[0] != 0) {
528 fprintf(stderr
, "\n ** Unexpected interleave: ");
529 dump_isodirrec(stderr
, isodirrec
);
530 fprintf(stderr
, "\n");
531 } else if (isodirrec
->ext_attr_length
[0] != 0) {
532 fprintf(stderr
, "\n ** Unexpected extended attribute length: ");
533 dump_isodirrec(stderr
, isodirrec
);
534 fprintf(stderr
, "\n");
541 add_entry(struct iso9660
*iso9660
, struct file_info
*file
)
543 /* Expand our pending files list as necessary. */
544 if (iso9660
->pending_files_used
>= iso9660
->pending_files_allocated
) {
545 struct file_info
**new_pending_files
;
546 int new_size
= iso9660
->pending_files_allocated
* 2;
550 new_pending_files
= malloc(new_size
* sizeof(new_pending_files
[0]));
551 if (new_pending_files
== NULL
)
552 __archive_errx(1, "Out of memory");
553 memcpy(new_pending_files
, iso9660
->pending_files
,
554 iso9660
->pending_files_allocated
* sizeof(new_pending_files
[0]));
555 if (iso9660
->pending_files
!= NULL
)
556 free(iso9660
->pending_files
);
557 iso9660
->pending_files
= new_pending_files
;
558 iso9660
->pending_files_allocated
= new_size
;
561 iso9660
->pending_files
[iso9660
->pending_files_used
++] = file
;
565 parse_rockridge(struct iso9660
*iso9660
, struct file_info
*file
,
566 const unsigned char *p
, const unsigned char *end
)
568 (void)iso9660
; /* UNUSED */
570 while (p
+ 4 < end
/* Enough space for another entry. */
571 && p
[0] >= 'A' && p
[0] <= 'Z' /* Sanity-check 1st char of name. */
572 && p
[1] >= 'A' && p
[1] <= 'Z' /* Sanity-check 2nd char of name. */
573 && p
+ p
[2] <= end
) { /* Sanity-check length. */
574 const unsigned char *data
= p
+ 4;
575 int data_length
= p
[2] - 4;
579 * Yes, each 'if' here does test p[0] again.
580 * Otherwise, the fall-through handling to catch
581 * unsupported extensions doesn't work.
585 if (p
[0] == 'C' && p
[1] == 'E' && version
== 1) {
587 * CE extension comprises:
588 * 8 byte sector containing extension
589 * 8 byte offset w/in above sector
590 * 8 byte length of continuation
592 file
->ce_offset
= toi(data
, 4)
593 * iso9660
->logical_block_size
595 file
->ce_size
= toi(data
+ 16, 4);
600 if (p
[0] == 'N' && p
[1] == 'M' && version
== 1
602 /* NM extension with flag byte == 0 */
604 * NM extension comprises:
608 /* TODO: Obey flags. */
609 char *old_name
= file
->name
;
611 data
++; /* Skip flag byte. */
613 file
->name
= malloc(data_length
+ 1);
614 if (file
->name
!= NULL
) {
616 memcpy(file
->name
, data
, data_length
);
617 file
->name
[data_length
] = '\0';
619 file
->name
= old_name
;
624 if (p
[0] == 'P' && p
[1] == 'D' && version
== 1) {
626 * PD extension is padding;
627 * contents are always ignored.
631 if (p
[0] == 'P' && p
[1] == 'X' && version
== 1) {
633 * PX extension comprises:
635 * 8 bytes for nlinks,
640 if (data_length
== 32) {
641 file
->mode
= toi(data
, 4);
642 file
->nlinks
= toi(data
+ 8, 4);
643 file
->uid
= toi(data
+ 16, 4);
644 file
->gid
= toi(data
+ 24, 4);
645 file
->inode
= toi(data
+ 32, 4);
651 if (p
[0] == 'R' && p
[1] == 'R' && version
== 1) {
652 iso9660
->seenRockridge
= 1;
654 * RR extension comprises:
655 * one byte flag value
657 /* TODO: Handle RR extension. */
662 if (p
[0] == 'S' && p
[1] == 'L' && version
== 1
665 /* SL extension with flags == 0 */
666 /* TODO: handle non-zero flag values. */
667 data
++; /* Skip flag byte. */
669 while (data_length
> 0) {
670 unsigned char flag
= *data
++;
671 unsigned char nlen
= *data
++;
675 archive_strcat(&file
->symlink
, "/");
679 case 0x01: /* Continue */
680 archive_strncat(&file
->symlink
,
681 (const char *)data
, nlen
);
684 case 0x02: /* Current */
685 archive_strcat(&file
->symlink
, ".");
687 case 0x04: /* Parent */
688 archive_strcat(&file
->symlink
, "..");
690 case 0x08: /* Root */
691 case 0x10: /* Volume root */
692 archive_string_empty(&file
->symlink
);
694 case 0x20: /* Hostname */
695 archive_strcat(&file
->symlink
, "hostname");
698 archive_strncat(&file
->symlink
,
699 (const char *)data
, nlen
);
702 /* TODO: issue a warning ? */
710 if (p
[0] == 'S' && p
[1] == 'P'
711 && version
== 1 && data_length
== 7
712 && data
[0] == (unsigned char)'\xbe'
713 && data
[1] == (unsigned char)'\xef') {
715 * SP extension stores the suspOffset
716 * (Number of bytes to skip between
717 * filename and SUSP records.)
718 * It is mandatory by the SUSP standard
721 * It allows SUSP to coexist with
722 * non-SUSP uses of the System
723 * Use Area by placing non-SUSP data
726 * TODO: Add a check for 'SP' in
727 * first directory entry, disable all SUSP
728 * processing if not found.
730 iso9660
->suspOffset
= data
[2];
733 if (p
[0] == 'S' && p
[1] == 'T'
734 && data_length
== 0 && version
== 1) {
736 * ST extension marks end of this
737 * block of SUSP entries.
739 * It allows SUSP to coexist with
740 * non-SUSP uses of the System
741 * Use Area by placing non-SUSP data
747 if (p
[0] == 'T' && p
[1] == 'F' && version
== 1) {
750 * TF extension comprises:
752 * create time (optional)
753 * modify time (optional)
754 * access time (optional)
755 * attribute time (optional)
756 * Time format and presence of fields
757 * is controlled by flag bits.
761 /* Use 17-byte time format. */
762 if (flag
& 1) /* Create time. */
764 if (flag
& 2) { /* Modify time. */
765 file
->mtime
= isodate17(data
);
768 if (flag
& 4) { /* Access time. */
769 file
->atime
= isodate17(data
);
772 if (flag
& 8) { /* Attribute time. */
773 file
->ctime
= isodate17(data
);
777 /* Use 7-byte time format. */
778 if (flag
& 1) /* Create time. */
780 if (flag
& 2) { /* Modify time. */
781 file
->mtime
= isodate7(data
);
784 if (flag
& 4) { /* Access time. */
785 file
->atime
= isodate7(data
);
788 if (flag
& 8) { /* Attribute time. */
789 file
->ctime
= isodate7(data
);
797 /* The FALLTHROUGHs above leave us here for
798 * any unsupported extension. */
800 const unsigned char *t
;
801 fprintf(stderr
, "\nUnsupported RRIP extension for %s\n", file
->name
);
802 fprintf(stderr
, " %c%c(%d):", p
[0], p
[1], data_length
);
803 for (t
= data
; t
< data
+ data_length
&& t
< data
+ 16; t
++)
804 fprintf(stderr
, " %02x", *t
);
805 fprintf(stderr
, "\n");
816 release_file(struct iso9660
*iso9660
, struct file_info
*file
)
818 struct file_info
*parent
;
820 if (file
->refcount
== 0) {
821 parent
= file
->parent
;
824 archive_string_free(&file
->symlink
);
826 if (parent
!= NULL
) {
828 release_file(iso9660
, parent
);
834 next_entry_seek(struct archive
*a
, struct iso9660
*iso9660
,
835 struct file_info
**pfile
)
837 struct file_info
*file
;
842 *pfile
= file
= next_entry(iso9660
);
844 return (ARCHIVE_EOF
);
846 /* CE area precedes actual file data? Ignore it. */
847 if (file
->ce_offset
> file
->offset
) {
848 fprintf(stderr
, " *** Discarding CE data.\n");
853 /* If CE exists, find and read it now. */
854 if (file
->ce_offset
> 0)
855 offset
= file
->ce_offset
;
857 offset
= file
->offset
;
859 /* Seek forward to the start of the entry. */
860 while (iso9660
->current_position
< offset
) {
861 ssize_t step
= offset
- iso9660
->current_position
;
865 if (step
> iso9660
->logical_block_size
)
866 step
= iso9660
->logical_block_size
;
867 bytes_read
= (a
->compression_read_ahead
)(a
, &buff
, step
);
868 if (bytes_read
<= 0) {
869 release_file(iso9660
, file
);
870 return (ARCHIVE_FATAL
);
872 if (bytes_read
> step
)
874 iso9660
->current_position
+= bytes_read
;
875 (a
->compression_read_consume
)(a
, bytes_read
);
878 /* We found body of file; handle it now. */
879 if (offset
== file
->offset
)
882 /* Found CE? Process it and push the file back onto list. */
883 if (offset
== file
->ce_offset
) {
885 ssize_t size
= file
->ce_size
;
887 const unsigned char *rr_start
;
891 bytes_read
= (a
->compression_read_ahead
)(a
, &p
, size
);
892 if (bytes_read
> size
)
894 rr_start
= (const unsigned char *)p
;
895 parse_rockridge(iso9660
, file
, rr_start
,
896 rr_start
+ bytes_read
);
897 (a
->compression_read_consume
)(a
, bytes_read
);
898 iso9660
->current_position
+= bytes_read
;
899 add_entry(iso9660
, file
);
904 static struct file_info
*
905 next_entry(struct iso9660
*iso9660
)
908 uint64_t least_end_offset
;
912 if (iso9660
->pending_files_used
< 1)
915 /* Assume the first file in the list is the earliest on disk. */
917 least_end_offset
= iso9660
->pending_files
[0]->offset
918 + iso9660
->pending_files
[0]->size
;
920 /* Now, try to find an earlier one. */
921 for (i
= 0; i
< iso9660
->pending_files_used
; i
++) {
922 /* Use the position of the file *end* as our comparison. */
923 uint64_t end_offset
= iso9660
->pending_files
[i
]->offset
924 + iso9660
->pending_files
[i
]->size
;
925 if (iso9660
->pending_files
[i
]->ce_offset
> 0
926 && iso9660
->pending_files
[i
]->ce_offset
< iso9660
->pending_files
[i
]->offset
)
927 end_offset
= iso9660
->pending_files
[i
]->ce_offset
928 + iso9660
->pending_files
[i
]->ce_size
;
929 if (least_end_offset
> end_offset
) {
931 least_end_offset
= end_offset
;
934 r
= iso9660
->pending_files
[least_index
];
935 iso9660
->pending_files
[least_index
]
936 = iso9660
->pending_files
[--iso9660
->pending_files_used
];
941 toi(const void *p
, int n
)
943 const unsigned char *v
= (const unsigned char *)p
;
945 return v
[0] + 256 * toi(v
+ 1, n
- 1);
952 isodate7(const void *p
)
955 const unsigned char *v
= (const unsigned char *)p
;
957 memset(&tm
, 0, sizeof(tm
));
959 tm
.tm_mon
= v
[1] - 1;
964 /* v[6] is the timezone offset, in 1/4-hour increments. */
965 offset
= ((const signed char *)p
)[6];
966 if (offset
> -48 && offset
< 52) {
967 tm
.tm_hour
-= offset
/ 4;
968 tm
.tm_min
-= (offset
% 4) * 15;
970 return (time_from_tm(&tm
));
974 isodate17(const void *p
)
977 const unsigned char *v
= (const unsigned char *)p
;
979 memset(&tm
, 0, sizeof(tm
));
980 tm
.tm_year
= (v
[0] - '0') * 1000 + (v
[1] - '0') * 100
981 + (v
[2] - '0') * 10 + (v
[3] - '0')
983 tm
.tm_mon
= (v
[4] - '0') * 10 + (v
[5] - '0');
984 tm
.tm_mday
= (v
[6] - '0') * 10 + (v
[7] - '0');
985 tm
.tm_hour
= (v
[8] - '0') * 10 + (v
[9] - '0');
986 tm
.tm_min
= (v
[10] - '0') * 10 + (v
[11] - '0');
987 tm
.tm_sec
= (v
[12] - '0') * 10 + (v
[13] - '0');
988 /* v[16] is the timezone offset, in 1/4-hour increments. */
989 offset
= ((const signed char *)p
)[16];
990 if (offset
> -48 && offset
< 52) {
991 tm
.tm_hour
-= offset
/ 4;
992 tm
.tm_min
-= (offset
% 4) * 15;
994 return (time_from_tm(&tm
));
998 * timegm() converts a struct tm to a time_t, except it isn't standard,
999 * so I provide my own function here that (ideally) is just a wrapper
1003 time_from_tm(struct tm
*t
)
1009 * Unfortunately, timegm() isn't standard. The standard
1010 * mktime() function is a close match, except that it uses
1011 * local timezone instead of GMT. Close enough for now.
1012 * Note that it is not possible to emulate timegm() using
1013 * standard interfaces:
1014 * * ANSI C90 does not even guarantee that time_t is
1015 * an arithmetic type, so time adjustments can only be
1016 * done by manipulating struct tm elements. You cannot
1017 * portably calculate time_t values.
1018 * * POSIX does promise that time_t is an arithmetic type
1019 * measured in seconds, so you can do time_t calculations
1020 * while remaining POSIX-compliant.
1021 * * Neither ANSI nor POSIX provides an easy way to measure
1022 * the timezone offset, so you can't adjust mktime() to
1023 * work like timegm().
1024 * * POSIX does not promise that the epoch begins in 1970,
1025 * so you can't write a portable timegm() function from
1028 time_t result
= mktime(t
);
1029 /* TODO: Find a way to improve this approximation to timegm(). */
1035 build_pathname(struct archive_string
*as
, struct file_info
*file
)
1037 if (file
->parent
!= NULL
&& file
->parent
->name
[0] != '\0') {
1038 build_pathname(as
, file
->parent
);
1039 archive_strcat(as
, "/");
1041 if (file
->name
[0] == '\0')
1042 archive_strcat(as
, ".");
1044 archive_strcat(as
, file
->name
);
1049 dump_isodirrec(FILE *out
, const struct iso9660_directory_record
*isodirrec
)
1051 fprintf(out
, " l %d,", isodirrec
->length
[0]);
1052 fprintf(out
, " a %d,", isodirrec
->ext_attr_length
[0]);
1053 fprintf(out
, " ext 0x%x,", toi(isodirrec
->extent
, 4));
1054 fprintf(out
, " s %d,", toi(isodirrec
->size
, 4));
1055 fprintf(out
, " f 0x%02x,", isodirrec
->flags
[0]);
1056 fprintf(out
, " u %d,", isodirrec
->file_unit_size
[0]);
1057 fprintf(out
, " ilv %d,", isodirrec
->interleave
[0]);
1058 fprintf(out
, " seq %d,", toi(isodirrec
->volume_sequence_number
,2));
1059 fprintf(out
, " nl %d:", isodirrec
->name_len
[0]);
1060 fprintf(out
, " `%.*s'", isodirrec
->name_len
[0], isodirrec
->name
);