diff options
| author | Pete Batard <pete@akeo.ie> | 2020-05-18 18:06:28 +0100 |
|---|---|---|
| committer | Pete Batard <pete@akeo.ie> | 2020-05-24 20:40:34 +0100 |
| commit | d758fa2253cca062e92ad0754a64c15a854db4ff (patch) | |
| tree | d2335e0660dd88e577a781b7191d8cb9e719ed2a | |
| parent | ac3041544f457df22ec7e6e78c87954b6d663577 (diff) | |
| download | libcdio-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.c | 6 | ||||
| -rw-r--r-- | example/isofile.c | 20 | ||||
| -rw-r--r-- | example/isofile2.c | 24 | ||||
| -rw-r--r-- | example/isolist.c | 14 | ||||
| -rw-r--r-- | include/cdio/iso9660.h | 34 | ||||
| -rw-r--r-- | lib/iso9660/iso9660_fs.c | 281 | ||||
| -rw-r--r-- | src/iso-info.c | 7 | ||||
| -rw-r--r-- | src/iso-read.c | 9 | ||||
| -rw-r--r-- | src/util.c | 25 | ||||
| -rw-r--r-- | test/testisocd.c | 4 | ||||
| -rw-r--r-- | test/testisocd2.c | 4 | ||||
| -rw-r--r-- | test/testisocd_joliet.c | 13 |
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; } @@ -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; } |
