diff --git a/example/Makefile.am b/example/Makefile.am index 13368c98..8301cc99 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.2 2003/12/24 11:05:48 uid67423 Exp $ +# $Id: Makefile.am,v 1.3 2004/01/10 03:03:08 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -20,7 +20,7 @@ # Things to regression testing #################################################### # -noinst_PROGRAMS = sample1 sample2 sample3 sample4 sample5 sample6 +noinst_PROGRAMS = sample1 sample2 sample3 sample4 sample5 sample6 sample7 INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS) @@ -30,3 +30,4 @@ sample3_LDADD = $(LIBCDIO_LIBS) sample4_LDADD = $(LIBCDIO_LIBS) sample5_LDADD = $(LIBCDIO_LIBS) sample6_LDADD = $(LIBCDIO_LIBS) $(LIBISO9660_LIBS) +sample7_LDADD = $(LIBCDIO_LIBS) $(LIBISO9660_LIBS) diff --git a/example/sample6.c b/example/sample6.c index 33271798..151d50d1 100644 --- a/example/sample6.c +++ b/example/sample6.c @@ -1,7 +1,7 @@ /* - $Id: sample6.c,v 1.1 2003/12/24 11:09:26 uid67423 Exp $ + $Id: sample6.c,v 1.2 2004/01/10 03:03:08 rocky Exp $ - Copyright (C) 2003 Rocky Bernstein + Copyright (C) 2003, 2004 Rocky Bernstein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -81,7 +81,8 @@ main(int argc, const char *argv[]) statbuf->lsn + (i / ISO_BLOCKSIZE), false) ) { - fprintf(stderr, "Error reading ISO 9660 file\n"); + fprintf(stderr, "Error reading ISO 9660 file at lsn %d\n", + statbuf->lsn + (i / ISO_BLOCKSIZE)); return 4; } diff --git a/example/sample7.c b/example/sample7.c new file mode 100644 index 00000000..6b8616a5 --- /dev/null +++ b/example/sample7.c @@ -0,0 +1,110 @@ +/* + $Id: sample7.c,v 1.1 2004/01/10 03:03:08 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Simple program to show using libiso9660 to extract a file. + */ +/* This is the ISO 9660 image. */ +#define ISO9660_IMAGE_PATH "../" +#define ISO9660_IMAGE ISO9660_IMAGE_PATH "test/copying.iso" + +#define ISO9660_FILENAME "/COPYING.;1" +#define LOCAL_FILENAME "copying" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include + +#include +#include +#include +#include +#include + +int +main(int argc, const char *argv[]) +{ + iso9660_stat_t *statbuf; + FILE *outfd; + int i; + + iso9660_t *iso = iso9660_open (ISO9660_IMAGE); + + if (NULL == iso) { + fprintf(stderr, "Sorry, couldn't open ISO 9660 image %s\n", ISO9660_IMAGE); + return 1; + } + + statbuf = iso9660_ifs_stat (iso, ISO9660_FILENAME); + + if (NULL == statbuf) + { + fprintf(stderr, + "Could not get ISO-9660 file information for file %s\n", + ISO9660_FILENAME); + return 2; + } + + if (!(outfd = fopen ("copying", "wb"))) + { + perror ("fopen()"); + return 3; + } + + /* Copy the blocks from the ISO-9660 filesystem to the local filesystem. */ + for (i = 0; i < statbuf->size; i += ISO_BLOCKSIZE) + { + char buf[ISO_BLOCKSIZE]; + + memset (buf, 0, ISO_BLOCKSIZE); + + if ( ISO_BLOCKSIZE != iso9660_iso_seek_read (iso, buf, statbuf->lsn + + (i / ISO_BLOCKSIZE), + 1) ) + { + fprintf(stderr, "Error reading ISO 9660 file at lsn %d\n", + statbuf->lsn + (i / ISO_BLOCKSIZE)); + return 4; + } + + + fwrite (buf, ISO_BLOCKSIZE, 1, outfd); + + if (ferror (outfd)) + { + perror ("fwrite()"); + return 5; + } + } + + fflush (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 (outfd), statbuf->size)) + perror ("ftruncate()"); + + fclose (outfd); + iso9660_close(iso); + return 0; +} diff --git a/include/cdio/iso9660.h b/include/cdio/iso9660.h index a569399e..89435996 100644 --- a/include/cdio/iso9660.h +++ b/include/cdio/iso9660.h @@ -1,8 +1,8 @@ /* - $Id: iso9660.h,v 1.34 2003/12/24 11:03:58 uid67423 Exp $ + $Id: iso9660.h,v 1.35 2004/01/10 03:03:08 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel - Copyright (C) 2003 Rocky Bernstein + Copyright (C) 2003, 2004 Rocky Bernstein See also iso9660.h by Eric Youngdale (1993). @@ -252,6 +252,29 @@ struct iso9660_stat { /* big endian!! */ PRAGMA_END_PACKED +/** This is an opaque structure. */ +typedef struct _iso9660 iso9660_t; + +/*! + Open an ISO 9660 image for reading. Maybe in the future we will have + flags and mode. NULL is returned on error. +*/ + iso9660_t *iso9660_open (const char *pathname /*flags, mode */); + +/*! + Close previously opened ISO 9660 image. + True is unconditionally returned. If there was an error false would + be returned. +*/ + bool iso9660_close (iso9660_t * iso); + + +/*! + Seek to a position and then read n bytes. Size read is returned. +*/ + long int iso9660_iso_seek_read (iso9660_t *iso, void *ptr, lsn_t start, + long int size); + /*==================================================== Time conversion ====================================================*/ @@ -392,18 +415,39 @@ iso9660_dir_calc_record_size (unsigned int namelen, unsigned int su_len); iso9660_stat_t *iso9660_find_fs_lsn(const CdIo *cdio, lsn_t lsn); +/*! + Given a directory pointer, find the filesystem entry that contains + lsn and return information about it. + + Returns stat_t of entry if we found lsn, or NULL otherwise. + */ +iso9660_stat_t *iso9660_find_ifs_lsn(const iso9660_t *iso, lsn_t lsn); + + /*! Get file status for pathname into stat. NULL is returned on error. */ iso9660_stat_t *iso9660_fs_stat (const CdIo *obj, const char pathname[], bool is_mode2); +/*! + Get file status for pathname into stat. NULL is returned on error. + */ +void *iso9660_ifs_stat (iso9660_t *iso, const char pathname[]); + + /*! Read pathname (a directory) and return a list of iso9660_stat_t of the files inside that. The caller must free the returned result. */ void * iso9660_fs_readdir (const CdIo *obj, const char pathname[], bool mode2); +/*! + Read pathname (a directory) and return a list of iso9660_stat_t + of the files inside that. The caller must free the returned result. +*/ +void * iso9660_ifs_readdir (const iso9660_t *iso, const char pathname[]); + uint8_t iso9660_get_dir_len(const iso9660_dir_t *idr); #if FIXME diff --git a/lib/_cdio_stdio.c b/lib/_cdio_stdio.c index 97af4025..a4f2a224 100644 --- a/lib/_cdio_stdio.c +++ b/lib/_cdio_stdio.c @@ -1,8 +1,8 @@ /* - $Id: _cdio_stdio.c,v 1.4 2003/04/22 12:09:09 rocky Exp $ + $Id: _cdio_stdio.c,v 1.5 2004/01/10 03:03:08 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel - Copyright (C) 2003 Rocky Bernstein + Copyright (C) 2003, 2004 Rocky Bernstein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ #include "_cdio_stream.h" #include "_cdio_stdio.h" -static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.4 2003/04/22 12:09:09 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.5 2004/01/10 03:03:08 rocky Exp $"; #define CDIO_STDIO_BUFSIZE (128*1024) @@ -145,7 +145,7 @@ _stdio_stat(void *user_data) must use feof(3) and ferror(3) to determine which occurred. */ static long -_stdio_read(void *user_data, void *buf, long count) +_stdio_read(void *user_data, void *buf, long int count) { _UserData *const ud = user_data; long read; diff --git a/lib/_cdio_stdio.h b/lib/_cdio_stdio.h index 21ef715a..558d2906 100644 --- a/lib/_cdio_stdio.h +++ b/lib/_cdio_stdio.h @@ -1,5 +1,5 @@ /* - $Id: _cdio_stdio.h,v 1.1 2003/03/24 19:01:09 rocky Exp $ + $Id: _cdio_stdio.h,v 1.2 2004/01/10 03:03:08 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003 Rocky Bernstein @@ -25,8 +25,14 @@ #include "_cdio_stream.h" -CdioDataSource* -cdio_stdio_new(const char pathname[]); +/*! + Initialize a new stdio stream reading from pathname. + A pointer to the stream is returned or NULL if there was an error. + + cdio_stream_free should be called on the returned value when you + don't need the stream any more. No other finalization is needed. + */ +CdioDataSource* cdio_stdio_new(const char pathname[]); #endif /* __CDIO_STREAM_STDIO_H__ */ diff --git a/lib/_cdio_stream.c b/lib/_cdio_stream.c index 83b6c8c8..597fb061 100644 --- a/lib/_cdio_stream.c +++ b/lib/_cdio_stream.c @@ -1,7 +1,7 @@ /* - $Id: _cdio_stream.c,v 1.7 2003/10/03 08:32:32 rocky Exp $ + $Id: _cdio_stream.c,v 1.8 2004/01/10 03:03:08 rocky Exp $ - Copyright (C) 2000 Herbert Valerio Riedel + Copyright (C) 2000, 2004 Herbert Valerio Riedel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #include #include "_cdio_stream.h" -static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.7 2003/10/03 08:32:32 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.8 2004/01/10 03:03:08 rocky Exp $"; /* * DataSource implementations diff --git a/lib/_cdio_stream.h b/lib/_cdio_stream.h index e3d74f40..eeb9b500 100644 --- a/lib/_cdio_stream.h +++ b/lib/_cdio_stream.h @@ -1,8 +1,8 @@ /* - $Id: _cdio_stream.h,v 1.6 2003/04/22 12:09:09 rocky Exp $ + $Id: _cdio_stream.h,v 1.7 2004/01/10 03:03:08 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel - Copyright (C) 2003 Rocky Bernstein + Copyright (C) 2003, 2004 Rocky Bernstein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -96,13 +96,13 @@ extern "C" { Otherwise, -1 is returned and the global variable errno is set to indi- cate the error. */ - long cdio_stream_seek(CdioDataSource* obj, long offset, int whence); + long int cdio_stream_seek(CdioDataSource* obj, long offset, int whence); /*! Return whatever size of stream reports, I guess unit size is bytes. On error return -1; */ - long cdio_stream_stat(CdioDataSource* obj); + long int cdio_stream_stat(CdioDataSource* obj); void cdio_stream_destroy(CdioDataSource* obj); diff --git a/lib/iso9660_fs.c b/lib/iso9660_fs.c index e1be8777..b999e6d7 100644 --- a/lib/iso9660_fs.c +++ b/lib/iso9660_fs.c @@ -1,8 +1,8 @@ /* - $Id: iso9660_fs.c,v 1.13 2003/11/16 19:30:45 rocky Exp $ + $Id: iso9660_fs.c,v 1.14 2004/01/10 03:03:08 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel - Copyright (C) 2003 Rocky Bernstein + Copyright (C) 2003, 2004 Rocky Bernstein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,10 +35,71 @@ #include "cdio_assert.h" #include "bytesex.h" #include "ds.h" +#include "_cdio_stdio.h" +#include "cdio_private.h" #include -static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.13 2003/11/16 19:30:45 rocky Exp $"; +static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.14 2004/01/10 03:03:08 rocky Exp $"; + +/* Implementation of iso9660_t type */ +struct _iso9660 { + CdioDataSource *stream; /* Stream pointer */ + void *env; /* environment. */ +}; + +/*! + Open an ISO 9660 image for reading. Maybe in the future we will have + flags and mode. NULL is returned on error. +*/ +iso9660_t * +iso9660_open (const char *pathname /*flags, mode */) +{ + iso9660_t *iso = (iso9660_t *) _cdio_malloc(sizeof(struct _iso9660)) ; + + if (NULL == iso) return NULL; + + iso->stream = cdio_stdio_new( pathname ); + if (NULL == iso->stream) { + free(iso); + return NULL; + } + + return iso; +} + + + +/*! + Close previously opened ISO 9660 image. + True is unconditionally returned. If there was an error false would + be returned. +*/ +bool +iso9660_close (iso9660_t *iso) +{ + if (NULL != iso) { + cdio_stream_destroy(iso->stream); + free(iso); + } + return true; +} + + + +/*! + Seek to a position and then read n blocks. Size read is returned. +*/ +long int +iso9660_iso_seek_read (iso9660_t *iso, void *ptr, lsn_t start, long int size) +{ + long int ret; + if (NULL == iso) return 0; + ret = cdio_stream_seek (iso->stream, start * ISO_BLOCKSIZE, SEEK_SET); + if (ret!=0) return 0; + return cdio_stream_read (iso->stream, ptr, ISO_BLOCKSIZE, size); +} + static iso9660_stat_t * _iso9660_dir_to_statbuf (const iso9660_dir_t *iso9660_dir, bool is_mode2) @@ -154,6 +215,22 @@ _fs_stat_root (const CdIo *cdio, bool is_mode2) return stat; } +static iso9660_stat_t * +_fs_stat_iso_root (iso9660_t *iso) +{ + char block[ISO_BLOCKSIZE] = { 0, }; + const iso9660_pvd_t *pvd = (void *) █ + const iso9660_dir_t *iso9660_dir = (void *) pvd->root_directory_record; + iso9660_stat_t *stat; + int ret; + + ret = iso9660_iso_seek_read (iso, block, ISO_PVD_SECTOR, 1); + if (ret!=ISO_BLOCKSIZE) return NULL; + + stat = _iso9660_dir_to_statbuf (iso9660_dir, true); + return stat; +} + static iso9660_stat_t * _fs_stat_traverse (const CdIo *cdio, const iso9660_stat_t *_root, char **splitpath, bool is_mode2) @@ -187,11 +264,11 @@ _fs_stat_traverse (const CdIo *cdio, const iso9660_stat_t *_root, if (is_mode2) { if (cdio_read_mode2_sectors (cdio, _dirbuf, _root->lsn, false, _root->secsize)) - cdio_assert_not_reached (); + return NULL; } else { if (cdio_read_mode1_sectors (cdio, _dirbuf, _root->lsn, false, _root->secsize)) - cdio_assert_not_reached (); + return NULL; } while (offset < (_root->secsize * ISO_BLOCKSIZE)) @@ -228,6 +305,74 @@ _fs_stat_traverse (const CdIo *cdio, const iso9660_stat_t *_root, return NULL; } +static iso9660_stat_t * +_fs_iso_stat_traverse (iso9660_t *iso, const iso9660_stat_t *_root, + char **splitpath) +{ + unsigned offset = 0; + uint8_t *_dirbuf = NULL; + iso9660_stat_t *stat; + int ret; + + if (!splitpath[0]) + { + unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1; + stat = _cdio_malloc(len); + memcpy(stat, _root, len); + return stat; + } + + if (_root->type == _STAT_FILE) + return NULL; + + cdio_assert (_root->type == _STAT_DIR); + + if (_root->size != ISO_BLOCKSIZE * _root->secsize) + { + cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", + (unsigned) _root->size, + (unsigned long int) ISO_BLOCKSIZE * _root->secsize); + } + + _dirbuf = _cdio_malloc (_root->secsize * ISO_BLOCKSIZE); + + ret = iso9660_iso_seek_read (iso, _dirbuf, _root->lsn, _root->secsize); + if (ret!=ISO_BLOCKSIZE*_root->secsize) return NULL; + + while (offset < (_root->secsize * ISO_BLOCKSIZE)) + { + const iso9660_dir_t *iso9660_dir = (void *) &_dirbuf[offset]; + iso9660_stat_t *stat; + + if (!iso9660_get_dir_len(iso9660_dir)) + { + offset++; + continue; + } + + stat = _iso9660_dir_to_statbuf (iso9660_dir, true); + + if (!strcmp (splitpath[0], stat->filename)) + { + iso9660_stat_t *ret_stat + = _fs_iso_stat_traverse (iso, stat, &splitpath[1]); + free(stat); + free (_dirbuf); + return ret_stat; + } + + free(stat); + + offset += iso9660_get_dir_len(iso9660_dir); + } + + cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); + + /* not found */ + free (_dirbuf); + return NULL; +} + /*! Get file status for pathname into stat. NULL is returned on error. */ @@ -238,8 +383,8 @@ iso9660_fs_stat (const CdIo *cdio, const char pathname[], bool is_mode2) char **splitpath; iso9660_stat_t *stat; - cdio_assert (cdio != NULL); - cdio_assert (pathname != NULL); + if (cdio == NULL) return NULL; + if (pathname == NULL) return NULL; root = _fs_stat_root (cdio, is_mode2); if (NULL == root) return NULL; @@ -252,6 +397,30 @@ iso9660_fs_stat (const CdIo *cdio, const char pathname[], bool is_mode2) return stat; } +/*! + Get file status for pathname into stat. NULL is returned on error. + */ +void * +iso9660_ifs_stat (iso9660_t *iso, const char pathname[]) +{ + iso9660_stat_t *root; + char **splitpath; + iso9660_stat_t *stat; + + if (iso == NULL) return NULL; + if (pathname == NULL) return NULL; + + root = _fs_stat_iso_root (iso); + if (NULL == root) return NULL; + + splitpath = _cdio_strsplit (pathname, '/'); + stat = _fs_iso_stat_traverse (iso, root, splitpath); + free(root); + _cdio_strfreev (splitpath); + + return stat; +} + /*! Read pathname (a directory) and return a list of iso9660_stat_t diff --git a/src/Makefile.am b/src/Makefile.am index fce1bebe..cb34de94 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.18 2003/11/18 03:35:19 rocky Exp $ +# $Id: Makefile.am,v 1.19 2004/01/10 03:03:08 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -35,12 +35,15 @@ cd_info_LDADD = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LIBPOPT_LIBS) $(CDDB_LIBS) cd_read_SOURCES = cd-read.c util.c util.h cd_read_LDADD = $(LIBCDIO_LIBS) $(LIBPOPT_LIBS) +iso_info_SOURCES = iso-info.c util.c util.h +iso_info_LDADD = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LIBPOPT_LIBS) + if BUILD_CDINFO_LINUX cdinfo_linux_SOURCES = cdinfo-linux.c cdinfo_linux_LDADD = $(LIBCDIO_LIBS) $(LIBPOPT_LIBS) -bin_PROGRAMS = cd-info cd-read cdinfo-linux +bin_PROGRAMS = cd-info cd-read cdinfo-linux iso-info else -bin_PROGRAMS = cd-info cd-read +bin_PROGRAMS = cd-info cd-read iso-info EXTRA_DIST = cdinfo-linux.c $(man_MANS) endif else