summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pete@akeo.ie>2020-05-18 18:06:28 +0100
committerPete Batard <pete@akeo.ie>2020-05-24 20:40:34 +0100
commitd758fa2253cca062e92ad0754a64c15a854db4ff (patch)
treed2335e0660dd88e577a781b7191d8cb9e719ed2a
parentac3041544f457df22ec7e6e78c87954b6d663577 (diff)
downloadlibcdio-d758fa2253cca062e92ad0754a64c15a854db4ff.tar.gz
Add support for ISO9660 multi extent files
This change expands the iso9660_stat_s struct to add support for processing multiple extents. The new structure is compatible with the current API, provided the DO_NOT_WANT_COMPATIBILITY macro is not defined. Examples and tests are also modified to use the updated API. Co-authored-by: Thomas Schmitt <scdbackup@gmx.net>
-rw-r--r--example/extract.c6
-rw-r--r--example/isofile.c20
-rw-r--r--example/isofile2.c24
-rw-r--r--example/isolist.c14
-rw-r--r--include/cdio/iso9660.h34
-rw-r--r--lib/iso9660/iso9660_fs.c281
-rw-r--r--src/iso-info.c7
-rw-r--r--src/iso-read.c9
-rw-r--r--src/util.c25
-rw-r--r--test/testisocd.c4
-rw-r--r--test/testisocd2.c4
-rw-r--r--test/testisocd_joliet.c13
12 files changed, 292 insertions, 149 deletions
diff --git a/example/extract.c b/example/extract.c
index a9f5a31..289e532 100644
--- a/example/extract.c
+++ b/example/extract.c
@@ -210,7 +210,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
fprintf(stderr, " Unable to create file\n");
goto out;
}
- i_file_length = p_statbuf->size;
+ i_file_length = p_statbuf->total_size;
for (i = 0; i_file_length > 0; i++) {
memset(buf, 0, ISO_BLOCKSIZE);
lsn = p_statbuf->lsn + i;
@@ -221,8 +221,8 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
}
fwrite(buf, (size_t)MIN(i_file_length, ISO_BLOCKSIZE), 1, fd);
if (ferror(fd)) {
- fprintf(stderr, " Error writing file %s: %s\n", psz_iso_name,
- strerror(errno));
+ fprintf(stderr, " Error writing file %s: %s\n", psz_iso_name,
+ strerror(errno));
goto out;
}
i_file_length -= ISO_BLOCKSIZE;
diff --git a/example/isofile.c b/example/isofile.c
index 2c582ed..d77a563 100644
--- a/example/isofile.c
+++ b/example/isofile.c
@@ -116,28 +116,28 @@ main(int argc, const char *argv[])
/* Copy the blocks from the ISO-9660 filesystem to the local filesystem. */
{
- const unsigned int i_blocks = CEILING(p_statbuf->size, ISO_BLOCKSIZE);
- for (i = 0; i < i_blocks ; i++)
+ const unsigned int i_blocks = CEILING(p_statbuf->total_size, ISO_BLOCKSIZE);
+ for (i = 0; i < i_blocks ; i++)
{
char buf[ISO_BLOCKSIZE];
const lsn_t lsn = p_statbuf->lsn + i;
memset (buf, 0, ISO_BLOCKSIZE);
-
+
if ( ISO_BLOCKSIZE != iso9660_iso_seek_read (p_iso, buf, lsn, 1) )
{
fprintf(stderr, "Error reading ISO 9660 file %s at LSN %lu\n",
psz_fname, (long unsigned int) lsn);
my_exit(4);
}
-
+
fwrite (buf, ISO_BLOCKSIZE, 1, p_outfd);
-
+
if (ferror (p_outfd))
- {
- perror ("fwrite()");
- my_exit(5);
- }
+ {
+ perror("fwrite()");
+ my_exit(5);
+ }
}
}
@@ -146,7 +146,7 @@ main(int argc, const char *argv[])
/* Make sure the file size has the exact same byte size. Without the
truncate below, the file will a multiple of ISO_BLOCKSIZE.
*/
- if (ftruncate (fileno (p_outfd), p_statbuf->size))
+ if (ftruncate (fileno (p_outfd), p_statbuf->total_size))
perror ("ftruncate()");
printf("Extraction of file '%s' from %s successful.\n",
diff --git a/example/isofile2.c b/example/isofile2.c
index a5cd039..255cdc2 100644
--- a/example/isofile2.c
+++ b/example/isofile2.c
@@ -136,36 +136,34 @@ main(int argc, const char *argv[])
/* Copy the blocks from the ISO-9660 filesystem to the local filesystem. */
{
- const unsigned int i_blocks = CEILING(p_statbuf->size, ISO_BLOCKSIZE);
+ const unsigned int i_blocks = CEILING(p_statbuf->total_size, ISO_BLOCKSIZE);
for (i = 0; i < i_blocks; i ++) {
char buf[ISO_BLOCKSIZE];
const lsn_t lsn = p_statbuf->lsn + i;
memset (buf, 0, ISO_BLOCKSIZE);
- if ( 0 != cdio_read_data_sectors (p_cdio, buf, lsn, ISO_BLOCKSIZE, 1) )
- {
- fprintf(stderr, "Error reading ISO 9660 file at lsn %lu\n",
- (long unsigned int) p_statbuf->lsn);
- my_exit(4);
- }
+ if ( 0 != cdio_read_data_sectors (p_cdio, buf, lsn, ISO_BLOCKSIZE, 1) ) {
+ fprintf(stderr, "Error reading ISO 9660 file at lsn %lu\n",
+ (long unsigned int) p_statbuf->lsn);
+ my_exit(4);
+ }
fwrite (buf, ISO_BLOCKSIZE, 1, p_outfd);
- if (ferror (p_outfd)) {
- perror ("fwrite()");
- my_exit(5);
+ if (ferror(p_outfd)) {
+ perror ("fwrite()");
+ my_exit(5);
}
- }
+ }
}
-
fflush (p_outfd);
/* Make sure the file size has the exact same byte size. Without the
truncate below, the file will a multiple of ISO_BLOCKSIZE.
*/
- if (ftruncate (fileno (p_outfd), p_statbuf->size))
+ if (ftruncate (fileno (p_outfd), p_statbuf->total_size))
perror ("ftruncate()");
printf("-- Extraction of file '%s' from '%s' successful.\n",
diff --git a/example/isolist.c b/example/isolist.c
index 1168250..489bff9 100644
--- a/example/isolist.c
+++ b/example/isolist.c
@@ -68,7 +68,7 @@ main(int argc, const char *argv[])
CdioListNode_t *p_entnode;
char const *psz_fname;
iso9660_t *p_iso;
- const char *psz_path="/";
+ const char *psz_path = "/";
if (argc > 1)
psz_fname = argv[1];
@@ -102,18 +102,20 @@ main(int argc, const char *argv[])
_CDIO_LIST_FOREACH (p_entnode, p_entlist)
{
char filename[4096];
+ double total_size;
iso9660_stat_t *p_statbuf =
(iso9660_stat_t *) _cdio_list_node_data (p_entnode);
iso9660_name_translate(p_statbuf->filename, filename);
- printf ("%s [LSN %6d] %8u %s%s\n",
- _STAT_DIR == p_statbuf->type ? "d" : "-",
- p_statbuf->lsn, p_statbuf->size, psz_path, filename);
+
+ total_size = (double) p_statbuf->total_size;
+ printf("%s [LSN %8d] %12.f %s%s\n",
+ _STAT_DIR == p_statbuf->type ? "d" : "-",
+ p_statbuf->lsn, total_size, psz_path, filename);
}
- iso9660_filelist_free(p_entlist);
+ iso9660_filelist_free(p_entlist);
}
-
iso9660_close(p_iso);
return 0;
}
diff --git a/include/cdio/iso9660.h b/include/cdio/iso9660.h
index c653cdb..0430890 100644
--- a/include/cdio/iso9660.h
+++ b/include/cdio/iso9660.h
@@ -163,6 +163,8 @@ extern const char ISO_STANDARD_ID[sizeof("CD001")-1];
#define ISO_STANDARD_ID "CD001"
+#define CDIO_EXTENT_BLOCKS(size) ((size + (ISO_BLOCKSIZE - 1)) / ISO_BLOCKSIZE)
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -529,17 +531,41 @@ typedef CdioList_t CdioISO9660DirList_t;
*/
struct iso9660_stat_s { /* big endian!! */
- iso_rock_statbuf_t rr; /**< Rock Ridge-specific fields */
+ iso_rock_statbuf_t rr; /**< Rock Ridge-specific fields */
struct tm tm; /**< time on entry - FIXME merge with
one of entries above, like ctime? */
lsn_t lsn; /**< start logical sector number */
- uint32_t size; /**< total size in bytes */
- uint32_t secsize; /**< number of sectors allocated */
+
+#ifndef DO_NOT_WANT_COMPATIBILITY
+
+ /* *** Deprecated Legacy API ***
+ Use .total_size and CDIO_EXTENT_BLOCKS.
+ */
+ uint32_t size; /**< size of the first extent, in bytes */
+ uint32_t secsize; /**< size of the first extent, in sectors */
+
+#endif /* DO_NOT_WANT_COMPATIBILITY */
+
+ /* Multi-extent aware size, in bytes.
+
+ It is guaranteed that the bytes are stored as gapless string in a
+ continguous sequence of blocks. I.e. they can be read sequentially
+ starting at iso9660_stat_s.lsn.
+ Data files which do not fulfil this promise cause a warning message
+ and are not represented by this type of struct.
+ (Directories are not allowed to have more than one extent and thus cannot
+ legally break the promise.)
+ */
+ uint64_t total_size;
+
+ /* NB: If you need to access the 'secsize' equivalent for an extent,
+ * you should use CDIO_EXTENT_BLOCKS(iso9660_stat_s.total_size) */
+
iso9660_xa_t xa; /**< XA attributes */
enum { _STAT_FILE = 1, _STAT_DIR = 2 } type;
bool b_xa;
- char filename[EMPTY_ARRAY_SIZE]; /**< filename */
+ char filename[EMPTY_ARRAY_SIZE]; /**< filename */
};
/** A mask used in iso9660_ifs_read_vd which allows what kinds
diff --git a/lib/iso9660/iso9660_fs.c b/lib/iso9660/iso9660_fs.c
index 538a90f..7a3264b 100644
--- a/lib/iso9660/iso9660_fs.c
+++ b/lib/iso9660/iso9660_fs.c
@@ -1,5 +1,7 @@
/*
Copyright (C) 2003-2008, 2011-2015, 2017 Rocky Bernstein <rocky@gnu.org>
+ Copyright (C) 2018, 2020 Pete Batard <pete@akeo.ie>
+ Copyright (C) 2018 Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software: you can redistribute it and/or modify
@@ -299,8 +301,8 @@ check_pvd (const iso9660_pvd_t *p_pvd, cdio_log_level_t log_level)
if (strncmp (p_pvd->id, ISO_STANDARD_ID, strlen (ISO_STANDARD_ID)))
{
- cdio_log (log_level, "unexpected ID encountered (expected `"
- ISO_STANDARD_ID "', got `%.5s')", p_pvd->id);
+ cdio_log (log_level, "unexpected ID encountered (expected '"
+ ISO_STANDARD_ID "', got '%.5s')", p_pvd->id);
return false;
}
return true;
@@ -777,39 +779,79 @@ iso9660_check_dir_block_end(iso9660_dir_t *p_iso9660_dir, unsigned *offset)
static iso9660_stat_t *
-_iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool_3way_t b_xa,
- uint8_t u_joliet_level)
+_iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir,
+ iso9660_stat_t *last_p_stat,
+ bool_3way_t b_xa, uint8_t u_joliet_level)
{
uint8_t dir_len= iso9660_get_dir_len(p_iso9660_dir);
iso711_t i_fname;
unsigned int stat_len;
- iso9660_stat_t *p_stat = NULL;
+ iso9660_stat_t *p_stat = last_p_stat;
+ char rr_fname[256] = "";
+ int i_rr_fname;
+ lsn_t extent_lsn;
+ bool first_extent;
if (!dir_len) return NULL;
- i_fname = from_711(p_iso9660_dir->filename.len);
+ i_fname = from_711(p_iso9660_dir->filename.len);
/* .. string in statbuf is one longer than in p_iso9660_dir's listing '\1' */
- stat_len = sizeof(iso9660_stat_t)+i_fname+2;
-
- p_stat = calloc(1, stat_len);
- if (!p_stat)
- {
+ stat_len = sizeof(iso9660_stat_t) + i_fname + 2;
+
+ /* Reuse multiextent p_stat if not NULL */
+ if (!p_stat) {
+ p_stat = calloc(1, stat_len);
+ first_extent = true;
+ } else {
+ first_extent = false;
+ }
+ if (!p_stat) {
cdio_warn("Couldn't calloc(1, %d)", stat_len);
return NULL;
- }
+ }
p_stat->type = (p_iso9660_dir->file_flags & ISO_DIRECTORY)
? _STAT_DIR : _STAT_FILE;
- p_stat->lsn = from_733 (p_iso9660_dir->extent);
- p_stat->size = from_733 (p_iso9660_dir->size);
- p_stat->secsize = _cdio_len2blocks (p_stat->size, ISO_BLOCKSIZE);
+
+ /* Test for gaps between extents. Important: Use previous .total_size */
+ extent_lsn = from_733 (p_iso9660_dir->extent);
+ if (p_stat->total_size > 0) {
+ /* This is a follow-up extent. Check for a gap. */
+ if (p_stat->lsn + p_stat->total_size / ISO_BLOCKSIZE != extent_lsn
+ || p_stat->total_size % ISO_BLOCKSIZE) {
+ /* Gap detected. Throw error. */
+ cdio_warn("Non-contiguous data extents with '%s'", p_stat->filename);
+ goto fail;
+ }
+ } else if (first_extent) {
+ p_stat->lsn = extent_lsn;
+ }
+ /* Only now update .total_size */
+ p_stat->total_size += from_733(p_iso9660_dir->size);
+
p_stat->rr.b3_rock = dunno; /*FIXME should do based on mask */
p_stat->b_xa = false;
- {
- char rr_fname[256] = "";
+#ifndef DO_NOT_WANT_COMPATIBILITY
+ if (first_extent) {
+ p_stat->size = from_733(p_iso9660_dir->size);
+ p_stat->secsize = CDIO_EXTENT_BLOCKS(p_stat->size);
+ }
+#endif /* DO_NOT_WANT_COMPATIBILITY */
- int i_rr_fname =
+ /* Only resolve the full filename when we're not dealing with extent */
+ if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)
+ {
+ /* Check if this is the last part of a multiextent file */
+ if (!first_extent) {
+ if (strlen(p_stat->filename) != i_fname ||
+ strncmp(p_stat->filename, &p_iso9660_dir->filename.str[1], i_fname) != 0) {
+ cdio_warn("Non consecutive multiextent file parts for '%s'",
+ p_stat->filename);
+ goto fail;
+ }
+ }
+ i_rr_fname =
#ifdef HAVE_ROCK
get_rock_ridge_filename(p_iso9660_dir, rr_fname, p_stat);
#else
@@ -852,13 +894,17 @@ _iso9660_dir_to_statbuf (iso9660_dir_t *p_iso9660_dir, bool_3way_t b_xa,
strncpy (p_stat->filename, &p_iso9660_dir->filename.str[1], i_fname);
}
}
+ } else {
+ /* Use the plain ISO-9660 name when dealing with a multiextent file part */
+ strncpy(p_stat->filename, &p_iso9660_dir->filename.str[1], i_fname);
}
-
iso9660_get_dtime(&(p_iso9660_dir->recording_time), true, &(p_stat->tm));
- if (dir_len < sizeof (iso9660_dir_t))
- goto fail;
+ if (dir_len < sizeof(iso9660_dir_t)) {
+ iso9660_stat_free(p_stat);
+ return NULL;
+ }
{
@@ -976,8 +1022,8 @@ _fs_stat_root (CdIo_t *p_cdio)
p_iso9660_dir = &(p_env->pvd.root_directory_record) ;
#endif
- p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, b_xa,
- p_env->u_joliet_level);
+ p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL,
+ b_xa, p_env->u_joliet_level);
return p_stat;
}
@@ -997,7 +1043,8 @@ _ifs_stat_root (iso9660_t *p_iso)
p_iso9660_dir = &(p_iso->pvd.root_directory_record) ;
#endif
- p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
+ p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL,
+ p_iso->b_xa,
p_iso->u_joliet_level);
return p_stat;
}
@@ -1008,8 +1055,11 @@ _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
{
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
+ uint32_t blocks;
iso9660_stat_t *p_stat;
generic_img_private_t *p_env = (generic_img_private_t *) p_cdio->env;
+ iso9660_stat_t *p_iso9660_stat = NULL;
+ bool skip_following_extents = false;
if (!splitpath[0])
{
@@ -1028,29 +1078,42 @@ _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
return NULL;
cdio_assert (_root->type == _STAT_DIR);
+ blocks = CDIO_EXTENT_BLOCKS(_root->total_size);
- _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
+ _dirbuf = calloc(1, blocks * ISO_BLOCKSIZE);
if (!_dirbuf)
{
- cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
+ cdio_warn("Couldn't calloc(1, %d)", blocks * ISO_BLOCKSIZE);
return NULL;
}
if (cdio_read_data_sectors (p_cdio, _dirbuf, _root->lsn, ISO_BLOCKSIZE,
- _root->secsize))
+ blocks))
return NULL;
- while (offset < (_root->secsize * ISO_BLOCKSIZE))
+ while (offset < (blocks * ISO_BLOCKSIZE))
{
iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
- iso9660_stat_t *p_iso9660_stat;
int cmp;
if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
continue;
- p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, dunno,
- p_env->u_joliet_level);
+ if (skip_following_extents) {
+ /* Do not register remaining extents of ill file */
+ p_iso9660_stat = NULL;
+ } else {
+ p_iso9660_stat = _iso9660_dir_to_statbuf (p_iso9660_dir,
+ p_iso9660_stat, dunno, p_env->u_joliet_level);
+ if (NULL == p_iso9660_stat)
+ skip_following_extents = true; /* Start ill file mode */
+ }
+ if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)
+ skip_following_extents = false; /* Ill or not: The file ends now */
+
+ if (NULL == p_iso9660_stat ||
+ (p_iso9660_dir->file_flags & ISO_MULTIEXTENT))
+ goto skip_to_next_record;
cmp = strcmp(splitpath[0], p_iso9660_stat->filename);
@@ -1064,7 +1127,7 @@ _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
if (!trans_fname) {
cdio_warn("can't allocate %lu bytes",
(long unsigned int) strlen(p_iso9660_stat->filename));
- free(p_iso9660_stat);
+ iso9660_stat_free(p_iso9660_stat);
return NULL;
}
iso9660_name_translate_ext(p_iso9660_stat->filename, trans_fname,
@@ -1083,11 +1146,14 @@ _fs_stat_traverse (const CdIo_t *p_cdio, const iso9660_stat_t *_root,
}
iso9660_stat_free(p_iso9660_stat);
+ p_iso9660_stat = NULL;
+
+skip_to_next_record:;
offset += iso9660_get_dir_len(p_iso9660_dir);
}
- cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
+ cdio_assert (offset == (blocks * ISO_BLOCKSIZE));
/* not found */
free (_dirbuf);
@@ -1100,11 +1166,13 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
{
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
- int ret;
+ uint32_t blocks;
+ int ret, cmp;
+ iso9660_stat_t *p_stat = NULL;
+ iso9660_dir_t *p_iso9660_dir = NULL;
if (!splitpath[0])
{
- iso9660_stat_t *p_stat;
unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1;
p_stat = calloc(1, len);
cdio_assert (p_stat != NULL);
@@ -1121,30 +1189,30 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
cdio_assert (_root->type == _STAT_DIR);
- _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
+ blocks = CDIO_EXTENT_BLOCKS(_root->total_size);
+ _dirbuf = calloc(1, blocks * ISO_BLOCKSIZE);
if (!_dirbuf)
{
- cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
+ cdio_warn("Couldn't calloc(1, %d)", blocks * ISO_BLOCKSIZE);
return NULL;
}
- ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
- if (ret!=ISO_BLOCKSIZE*_root->secsize) {
+ ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, blocks);
+ if (ret != blocks * ISO_BLOCKSIZE) {
free(_dirbuf);
return NULL;
}
- while (offset < (_root->secsize * ISO_BLOCKSIZE))
+ for (offset = 0; offset < (blocks * ISO_BLOCKSIZE);
+ offset += iso9660_get_dir_len(p_iso9660_dir))
{
- iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
- iso9660_stat_t *p_stat;
- int cmp;
+ p_iso9660_dir = (void *) &_dirbuf[offset];
if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
continue;
- p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
- p_iso->u_joliet_level);
+ p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_stat,
+ p_iso->b_xa, p_iso->u_joliet_level);
if (!p_stat) {
cdio_warn("Bad directory information for %s", splitpath[0]);
@@ -1152,6 +1220,10 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
return NULL;
}
+ /* If we have multiextent file parts, loop until the last one */
+ if (p_iso9660_dir->file_flags & ISO_MULTIEXTENT)
+ continue;
+
cmp = strcmp(splitpath[0], p_stat->filename);
if ( 0 != cmp && 0 == p_iso->u_joliet_level
@@ -1164,7 +1236,7 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
if (!trans_fname) {
cdio_warn("can't allocate %lu bytes",
(long unsigned int) strlen(p_stat->filename));
- free(p_stat);
+ iso9660_stat_free(p_stat);
return NULL;
}
iso9660_name_translate_ext(p_stat->filename, trans_fname,
@@ -1182,11 +1254,10 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
return ret_stat;
}
iso9660_stat_free(p_stat);
-
- offset += iso9660_get_dir_len(p_iso9660_dir);
+ p_stat = NULL;
}
- cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
+ cdio_assert (offset == (blocks * ISO_BLOCKSIZE));
/* not found */
free (_dirbuf);
@@ -1227,7 +1298,7 @@ iso9660_fs_stat (CdIo_t *p_cdio, const char psz_path[])
p_psz_splitpath = _cdio_strsplit (psz_path, '/');
p_stat = _fs_stat_traverse (p_cdio, p_root, p_psz_splitpath);
- free(p_root);
+ iso9660_stat_free(p_root);
_cdio_strfreev (p_psz_splitpath);
return p_stat;
@@ -1260,7 +1331,7 @@ fs_stat_translate (void *p_image, stat_root_t stat_root,
p_psz_splitpath = _cdio_strsplit (psz_path, '/');
p_stat = stat_traverse (p_image, p_root, p_psz_splitpath);
- free(p_root);
+ iso9660_stat_free(p_root);
_cdio_strfreev (p_psz_splitpath);
return p_stat;
@@ -1330,7 +1401,7 @@ iso9660_ifs_stat (iso9660_t *p_iso, const char psz_path[])
splitpath = _cdio_strsplit (psz_path, '/');
stat = _fs_iso_stat_traverse (p_iso, p_root, splitpath);
- free(p_root);
+ iso9660_stat_free(p_root);
_cdio_strfreev (splitpath);
return stat;
@@ -1351,6 +1422,8 @@ CdioISO9660FileList_t *
iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
{
generic_img_private_t *p_env;
+ iso9660_dir_t *p_iso9660_dir;
+ iso9660_stat_t *p_iso9660_stat = NULL;
iso9660_stat_t *p_stat;
if (!p_cdio) return NULL;
@@ -1369,40 +1442,56 @@ iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
{
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
+ uint32_t blocks = CDIO_EXTENT_BLOCKS(p_stat->total_size);
CdioISO9660DirList_t *retval = _cdio_list_new ();
+ bool skip_following_extents = false;
- _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE);
+ _dirbuf = calloc(1, blocks * ISO_BLOCKSIZE);
if (!_dirbuf)
{
- cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
+ cdio_warn("Couldn't calloc(1, %d)", blocks * ISO_BLOCKSIZE);
iso9660_stat_free(p_stat);
iso9660_dirlist_free(retval);
return NULL;
}
if (cdio_read_data_sectors (p_cdio, _dirbuf, p_stat->lsn,
- ISO_BLOCKSIZE, p_stat->secsize)) {
+ ISO_BLOCKSIZE, blocks)) {
iso9660_stat_free(p_stat);
iso9660_dirlist_free(retval);
return NULL;
}
- while (offset < (p_stat->secsize * ISO_BLOCKSIZE))
+ while (offset < (blocks * ISO_BLOCKSIZE))
{
- iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
- iso9660_stat_t *p_iso9660_stat;
+ p_iso9660_dir = (void *) &_dirbuf[offset];
if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
continue;
- p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, dunno,
- p_env->u_joliet_level);
- _cdio_list_append (retval, p_iso9660_stat);
+ if (skip_following_extents) {
+ /* Do not register remaining extents of ill file */
+ p_iso9660_stat = NULL;
+ } else {
+ p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir,
+ p_iso9660_stat, dunno,
+ p_env->u_joliet_level);
+ if (NULL == p_iso9660_stat)
+ skip_following_extents = true; /* Start ill file mode */
+ }
+ if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)
+ skip_following_extents = false; /* Ill or not: The file ends now */
+
+ if ((p_iso9660_stat) &&
+ ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)) {
+ _cdio_list_append (retval, p_iso9660_stat);
+ p_iso9660_stat = NULL;
+ }
offset += iso9660_get_dir_len(p_iso9660_dir);
}
- cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE));
+ cdio_assert (offset == (blocks * ISO_BLOCKSIZE));
free(_dirbuf);
iso9660_stat_free(p_stat);
@@ -1417,6 +1506,8 @@ iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
CdioISO9660FileList_t *
iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
{
+ iso9660_dir_t *p_iso9660_dir;
+ iso9660_stat_t *p_iso9660_stat = NULL;
iso9660_stat_t *p_stat;
if (!p_iso) return NULL;
@@ -1434,13 +1525,14 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
long int ret;
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
+ uint32_t blocks = CDIO_EXTENT_BLOCKS(p_stat->total_size);
CdioList_t *retval = _cdio_list_new ();
- const size_t dirbuf_len = p_stat->secsize * ISO_BLOCKSIZE;
-
+ const size_t dirbuf_len = blocks * ISO_BLOCKSIZE;
+ bool skip_following_extents = false;
if (!dirbuf_len)
{
- cdio_warn("Invalid directory buffer sector size %u", p_stat->secsize);
+ cdio_warn("Invalid directory buffer sector size %u", blocks);
iso9660_stat_free(p_stat);
_cdio_list_free (retval, true, NULL);
return NULL;
@@ -1455,7 +1547,7 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
return NULL;
}
- ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
+ ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, blocks);
if (ret != dirbuf_len) {
_cdio_list_free (retval, true, NULL);
iso9660_stat_free(p_stat);
@@ -1465,20 +1557,28 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
while (offset < (dirbuf_len))
{
- iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
- iso9660_stat_t *p_iso9660_stat;
+ p_iso9660_dir = (void *) &_dirbuf[offset];
if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
continue;
- p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, p_iso->b_xa,
- p_iso->u_joliet_level);
-
- if (p_iso9660_stat)
- _cdio_list_append (retval, p_iso9660_stat);
- else {
- cdio_warn("Invalid directory stat at offset %lu", (unsigned long)offset);
- break;
+ if (skip_following_extents) {
+ /* Do not register remaining extents of ill file */
+ p_iso9660_stat = NULL;
+ } else {
+ p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir,
+ p_iso9660_stat,
+ p_iso->b_xa,
+ p_iso->u_joliet_level);
+ if (NULL == p_iso9660_stat)
+ skip_following_extents = true; /* Start ill file mode */
+ }
+ if ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)
+ skip_following_extents = false; /* Ill or not: The file ends now */
+ if ((p_iso9660_stat) &&
+ ((p_iso9660_dir->file_flags & ISO_MULTIEXTENT) == 0)) {
+ _cdio_list_append(retval, p_iso9660_stat);
+ p_iso9660_stat = NULL;
}
offset += iso9660_get_dir_len(p_iso9660_dir);
@@ -1540,7 +1640,8 @@ find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
}
if (statbuf->lsn == lsn) {
- const unsigned int len2 = sizeof(iso9660_stat_t)+strlen(statbuf->filename)+1;
+ const unsigned int len2 = sizeof(iso9660_stat_t) +
+ strlen(statbuf->filename) + 1;
iso9660_stat_t *ret_stat = calloc(1, len2);
if (!ret_stat)
{
@@ -1551,9 +1652,9 @@ find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
return NULL;
}
memcpy(ret_stat, statbuf, len2);
- iso9660_filelist_free (entlist);
+ iso9660_filelist_free (entlist);
iso9660_dirlist_free(dirlist);
- return ret_stat;
+ return ret_stat;
}
}
@@ -1573,7 +1674,7 @@ find_lsn_recurse (void *p_image, iso9660_readdir_t iso9660_readdir,
ppsz_full_filename);
if (NULL != ret_stat) {
- iso9660_dirlist_free(dirlist);
+ iso9660_dirlist_free(dirlist);
return ret_stat;
}
}
@@ -1723,6 +1824,7 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
{
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
+ uint32_t blocks;
int ret;
bool_3way_t have_rr = nope;
@@ -1733,20 +1835,21 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
cdio_assert (_root->type == _STAT_DIR);
- _dirbuf = calloc(1, _root->secsize * ISO_BLOCKSIZE);
+ blocks = CDIO_EXTENT_BLOCKS(_root->total_size);
+ _dirbuf = calloc(1, blocks * ISO_BLOCKSIZE);
if (!_dirbuf)
{
- cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE);
+ cdio_warn("Couldn't calloc(1, %d)", blocks * ISO_BLOCKSIZE);
return dunno;
}
- ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize);
- if (ret!=ISO_BLOCKSIZE*_root->secsize) {
+ ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, blocks);
+ if (ret != blocks * ISO_BLOCKSIZE) {
free(_dirbuf);
return false;
}
- while (offset < (_root->secsize * ISO_BLOCKSIZE))
+ while (offset < (blocks * ISO_BLOCKSIZE))
{
iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset];
iso9660_stat_t *p_stat;
@@ -1755,7 +1858,7 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
if (iso9660_check_dir_block_end(p_iso9660_dir, &offset))
continue;
- p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa,
+ p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, NULL, p_iso->b_xa,
p_iso->u_joliet_level);
have_rr = p_stat->rr.b3_rock;
if ( have_rr != yep) {
@@ -1765,7 +1868,7 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
have_rr = iso_have_rr_traverse (p_iso, p_stat, &splitpath[i_last_component],
pu_file_limit);
}
- free(p_stat);
+ iso9660_stat_free(p_stat);
if (have_rr != nope) {
free (_dirbuf);
return have_rr;
@@ -1779,7 +1882,7 @@ iso_have_rr_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
}
}
- cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE));
+ cdio_assert (offset == (blocks * ISO_BLOCKSIZE));
/* not found */
free (_dirbuf);
@@ -1815,7 +1918,7 @@ iso9660_have_rr(iso9660_t *p_iso, uint64_t u_file_limit)
if (u_file_limit == 0) u_file_limit = UINT64_MAX;
is_rr = iso_have_rr_traverse (p_iso, p_root, p_psz_splitpath, &u_file_limit);
- free(p_root);
+ iso9660_stat_free(p_root);
free(p_psz_splitpath[0]);
free(p_psz_splitpath[1]);
diff --git a/src/iso-info.c b/src/iso-info.c
index 12c035e..cfca76f 100644
--- a/src/iso-info.c
+++ b/src/iso-info.c
@@ -54,10 +54,12 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
#if 0
#define STRONG "\033[1m"
@@ -300,7 +302,8 @@ print_iso9660_recurse (iso9660_t *p_iso, const char psz_path[],
psz_iso_name, translated_name);
} else {
if ( strcmp (psz_iso_name, ".") && strcmp (psz_iso_name, ".."))
- printf("%9u %s%s\n", (unsigned int) p_statbuf->size, psz_path,
+ printf("%9" PRIu64 " %s%s\n", p_statbuf->total_size,
+ psz_path,
yep == p_statbuf->rr.b3_rock
? psz_iso_name : translated_name);
}
diff --git a/src/iso-read.c b/src/iso-read.c
index 852112a..aeacefc 100644
--- a/src/iso-read.c
+++ b/src/iso-read.c
@@ -211,7 +211,7 @@ static int read_iso_file(const char *iso_name, const char *src,
FILE *outfd, size_t *bytes_written)
{
iso9660_stat_t *statbuf;
- int i;
+ uint64_t i;
iso9660_t *iso;
iso = iso9660_open (iso_name);
@@ -234,12 +234,13 @@ static int read_iso_file(const char *iso_name, const char *src,
report(stderr,
"%s: iso-info may be able to show the contents of %s.\n",
program_name, iso_name);
+ iso9660_close(iso);
return 2;
}
/* Copy the blocks from the ISO-9660 filesystem to the local filesystem. */
- for (i = 0; i < statbuf->size; i += ISO_BLOCKSIZE)
+ for (i = 0; i < statbuf->total_size; i += ISO_BLOCKSIZE)
{
char buf[ISO_BLOCKSIZE];
@@ -260,12 +261,14 @@ static int read_iso_file(const char *iso_name, const char *src,
if (ferror (outfd))
{
perror ("fwrite()");
+ iso9660_stat_free(statbuf);
+ iso9660_close(iso);
return 5;
}
}
iso9660_close(iso);
- *bytes_written = statbuf->size;
+ *bytes_written = statbuf->total_size;
iso9660_stat_free(statbuf);
return 0;
}
diff --git a/src/util.c b/src/util.c
index dde2f40..d115e82 100644
--- a/src/util.c
+++ b/src/util.c
@@ -480,18 +480,20 @@ print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa,
const char *psz_name_translated)
{
char date_str[30];
+ double total_size, m2f2_size;
#ifdef HAVE_ROCK
if (yep == p_statbuf->rr.b3_rock && b_rock) {
- report ( stdout, " %s %3d %d %d [LSN %6lu] %9u",
+ total_size = (double) (S_ISLNK(p_statbuf->rr.st_mode)
+ ? strlen(p_statbuf->rr.psz_symlink)
+ : p_statbuf->total_size );
+ report ( stdout, " %s %3d %d %d [LSN %6lu] %9.f",
iso9660_get_rock_attr_str (p_statbuf->rr.st_mode),
p_statbuf->rr.st_nlinks,
p_statbuf->rr.st_uid,
p_statbuf->rr.st_gid,
(long unsigned int) p_statbuf->lsn,
- S_ISLNK(p_statbuf->rr.st_mode)
- ? strlen(p_statbuf->rr.psz_symlink)
- : (unsigned int) p_statbuf->size );
+ total_size );
} else
#endif
@@ -503,17 +505,18 @@ print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa,
p_statbuf->xa.filenum,
(long unsigned int) p_statbuf->lsn );
+ total_size = (double) p_statbuf->total_size;
if (uint16_from_be(p_statbuf->xa.attributes) & XA_ATTR_MODE2FORM2) {
- report ( stdout, "%9u (%9u)",
- (unsigned int) p_statbuf->secsize * M2F2_SECTOR_SIZE,
- (unsigned int) p_statbuf->size );
+ m2f2_size = (double) CDIO_EXTENT_BLOCKS(p_statbuf->total_size)
+ * M2F2_SECTOR_SIZE;
+ report ( stdout, "%9.f (%9.f)", m2f2_size, total_size );
} else
- report (stdout, "%9u", (unsigned int) p_statbuf->size);
+ report (stdout, "%9.f", total_size);
} else {
- report ( stdout," %c [LSN %6lu] %9u",
+ total_size = (double) p_statbuf->total_size;
+ report ( stdout," %c [LSN %6lu] %9.f",
(p_statbuf->type == _STAT_DIR) ? 'd' : '-',
- (long unsigned int) p_statbuf->lsn,
- (unsigned int) p_statbuf->size );
+ (long unsigned int) p_statbuf->lsn, total_size );
}
if (yep == p_statbuf->rr.b3_rock && b_rock) {
diff --git a/test/testisocd.c b/test/testisocd.c
index 6b1f60b..ff83cb7 100644
--- a/test/testisocd.c
+++ b/test/testisocd.c
@@ -108,7 +108,7 @@ main(int argc, const char *argv[])
/* Compare the two statbufs. */
if (p_statbuf->lsn != p_statbuf2->lsn ||
- p_statbuf->size != p_statbuf2->size ||
+ p_statbuf->total_size != p_statbuf2->total_size ||
p_statbuf->type != p_statbuf2->type) {
fprintf(stderr, "File stat information between fs_stat and "
"fs_find_lsn isn't the same\n");
@@ -151,6 +151,8 @@ main(int argc, const char *argv[])
iso9660_stat_free(p_statbuf2);
iso9660_stat_free(p_statbuf3);
cdio_destroy(p_cdio);
+ if (NULL != psz_path)
+ free(psz_path);
exit(rc);
}
}
diff --git a/test/testisocd2.c b/test/testisocd2.c
index a118776..46dbebb 100644
--- a/test/testisocd2.c
+++ b/test/testisocd2.c
@@ -112,7 +112,7 @@ main(int argc, const char *argv[])
/* Compare the two statbufs. */
if (p_statbuf->lsn != p_statbuf2->lsn ||
- p_statbuf->size != p_statbuf2->size ||
+ p_statbuf->total_size != p_statbuf2->total_size ||
p_statbuf->type != p_statbuf2->type) {
fprintf(stderr, "File stat information between fs_stat and "
@@ -122,7 +122,7 @@ main(int argc, const char *argv[])
}
if (p_statbuf3->lsn != p_statbuf2->lsn ||
- p_statbuf3->size != p_statbuf2->size ||
+ p_statbuf3->total_size != p_statbuf2->total_size ||
p_statbuf3->type != p_statbuf2->type) {
rc = 4;
goto exit;
diff --git a/test/testisocd_joliet.c b/test/testisocd_joliet.c
index 8eedc2f..07090ac 100644
--- a/test/testisocd_joliet.c
+++ b/test/testisocd_joliet.c
@@ -112,18 +112,21 @@ main(int argc, const char *argv[])
iso9660_ifs_find_lsn_with_path (p_iso, i_lsn, &psz_path);
int rc=0;
const unsigned int statbuf_test_size = 100;
+ double total_size;
/* Compare the two statbufs. */
if (p_statbuf->lsn != p_statbuf2->lsn ||
- p_statbuf->size != p_statbuf2->size ||
+ p_statbuf->total_size != p_statbuf2->total_size ||
p_statbuf->type != p_statbuf2->type) {
fprintf(stderr, "File stat information between fs_stat and "
"iso9660_ifs_find_lsn isn't the same\n");
- printf("statbuf lsn: %d, size: %d, type: %d\n",
- p_statbuf->lsn, p_statbuf->size, p_statbuf->type);
- printf("statbuf2 lsn: %d, size: %d, type: %d\n",
- p_statbuf2->lsn, p_statbuf2->size, p_statbuf2->type);
+ total_size = p_statbuf->total_size;
+ printf("statbuf lsn: %d, size: %4.f, type: %d\n",
+ p_statbuf->lsn, total_size, p_statbuf->type);
+ total_size = p_statbuf2->total_size;
+ printf("statbuf2 lsn: %d, size: %4.f, type: %d\n",
+ p_statbuf2->lsn, total_size, p_statbuf2->type);
rc=3;
goto exit;
}