Makefile.am: add CDIO_ to all #defines in cdio_config.h

extract.c: give filename on extract errors and convert encoding to unix.
This commit is contained in:
R. Bernstein
2012-03-04 13:38:35 -05:00
parent 8eabfdd37a
commit 39bd8104b8
2 changed files with 306 additions and 305 deletions

View File

@@ -1,300 +1,302 @@
/* /*
Copyright (C) 2012 Pete Batard <pete@akeo.ie> Copyright (C) 2012 Pete Batard <pete@akeo.ie>
Based on samples copyright (c) 2003-2011 Rocky Bernstein <rocky@gnu.org> Based on samples copyright (c) 2003-2011 Rocky Bernstein <rocky@gnu.org>
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Extract the full contents of either an UDF or ISO9660 image file. /* Extract the full contents of either an UDF or ISO9660 image file.
TODO: timestamp preservation, file permissions, Unicode TODO: timestamp preservation, file permissions, Unicode
*/ */
/* To handle files > 2 GB, we may need the Large File Support settings /* To handle files > 2 GB, we may need the Large File Support settings
defined in config.h. Comes first, as stdio.h depends on it. */ defined in config.h. Comes first, as stdio.h depends on it. */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#define __CDIO_CONFIG_H__ 1 #define __CDIO_CONFIG_H__ 1
#endif #endif
#ifdef HAVE_STDIO_H #ifdef HAVE_STDIO_H
#include <stdio.h> #include <stdio.h>
#endif #endif
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>
#endif #endif
#ifdef HAVE_ERRNO_H #ifdef HAVE_ERRNO_H
#include <errno.h> #include <errno.h>
#endif #endif
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
#include <direct.h> #include <direct.h>
#else #else
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#define _mkdir(a) mkdir(a, S_IRWXU) #define _mkdir(a) mkdir(a, S_IRWXU)
#endif #endif
#if !defined(HAVE_SNPRINTF) #if !defined(HAVE_SNPRINTF)
/* Fallback to unsafe 'sprintf' */ /* Fallback to unsafe 'sprintf' */
#define snprintf(str, size, format, ...) sprintf(str, format, __VA_ARGS__) #define snprintf(str, size, format, ...) sprintf(str, format, __VA_ARGS__)
#endif #endif
#include <cdio/cdio.h> #include <cdio/cdio.h>
#include <cdio/logging.h> #include <cdio/logging.h>
#include <cdio/iso9660.h> #include <cdio/iso9660.h>
#include <cdio/udf.h> #include <cdio/udf.h>
#ifndef MIN #ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif #endif
#define print_vd_info(title, fn) \ #define print_vd_info(title, fn) \
if (fn(p_iso, &psz_str)) { \ if (fn(p_iso, &psz_str)) { \
printf(title ": %s\n", psz_str); \ printf(title ": %s\n", psz_str); \
} \ } \
free(psz_str); \ free(psz_str); \
psz_str = NULL; psz_str = NULL;
const char *psz_extract_dir; const char *psz_extract_dir;
static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path) static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path)
{ {
FILE *fd = NULL; FILE *fd = NULL;
int i_length; int i_length;
char* psz_fullpath; char* psz_fullpath;
const char* psz_basename; const char* psz_basename;
udf_dirent_t *p_udf_dirent2; udf_dirent_t *p_udf_dirent2;
uint8_t buf[UDF_BLOCKSIZE]; uint8_t buf[UDF_BLOCKSIZE];
int64_t i_read, i_file_length; int64_t i_read, i_file_length;
if ((p_udf_dirent == NULL) || (psz_path == NULL)) if ((p_udf_dirent == NULL) || (psz_path == NULL))
return 1; return 1;
while (udf_readdir(p_udf_dirent)) { while (udf_readdir(p_udf_dirent)) {
psz_basename = udf_get_filename(p_udf_dirent); psz_basename = udf_get_filename(p_udf_dirent);
i_length = 3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir); i_length = 3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir);
psz_fullpath = (char*)calloc(sizeof(char), i_length); psz_fullpath = (char*)calloc(sizeof(char), i_length);
if (psz_fullpath == NULL) { if (psz_fullpath == NULL) {
fprintf(stderr, "Error allocating file name\n"); fprintf(stderr, "Error allocating file name\n");
goto out; goto out;
} }
i_length = snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename); i_length = snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename);
if (i_length < 0) { if (i_length < 0) {
goto out; goto out;
} }
printf("Extracting: %s\n", psz_fullpath); printf("Extracting: %s\n", psz_fullpath);
if (udf_is_dir(p_udf_dirent)) { if (udf_is_dir(p_udf_dirent)) {
_mkdir(psz_fullpath); _mkdir(psz_fullpath);
p_udf_dirent2 = udf_opendir(p_udf_dirent); p_udf_dirent2 = udf_opendir(p_udf_dirent);
if (p_udf_dirent2 != NULL) { if (p_udf_dirent2 != NULL) {
if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)])) if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)]))
goto out; goto out;
} }
} else { } else {
fd = fopen(psz_fullpath, "wb"); fd = fopen(psz_fullpath, "wb");
if (fd == NULL) { if (fd == NULL) {
fprintf(stderr, " Unable to create file\n"); fprintf(stderr, " Unable to create file %s\n", psz_fullpath);
goto out; goto out;
} }
i_file_length = udf_get_file_length(p_udf_dirent); i_file_length = udf_get_file_length(p_udf_dirent);
while (i_file_length > 0) { while (i_file_length > 0) {
memset(buf, 0, UDF_BLOCKSIZE); memset(buf, 0, UDF_BLOCKSIZE);
i_read = udf_read_block(p_udf_dirent, buf, 1); i_read = udf_read_block(p_udf_dirent, buf, 1);
if (i_read < 0) { if (i_read < 0) {
fprintf(stderr, " Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]); fprintf(stderr, " Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]);
goto out; goto out;
} }
fwrite(buf, (size_t)MIN(i_file_length, i_read), 1, fd); fwrite(buf, (size_t)MIN(i_file_length, i_read), 1, fd);
if (ferror(fd)) { if (ferror(fd)) {
fprintf(stderr, " Error writing file: %s\n", strerror(errno)); fprintf(stderr, " Error writing file %s: %s\n", psz_fullpath,
goto out; strerror(errno));
} goto out;
i_file_length -= i_read; }
} i_file_length -= i_read;
fclose(fd); }
fd = NULL; fclose(fd);
} fd = NULL;
free(psz_fullpath); }
} free(psz_fullpath);
return 0; }
return 0;
out:
if (fd != NULL) out:
fclose(fd); if (fd != NULL)
free(psz_fullpath); fclose(fd);
return 1; free(psz_fullpath);
} return 1;
}
static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
{ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
FILE *fd = NULL; {
int i_length, r = 1; FILE *fd = NULL;
char psz_fullpath[4096], *psz_basename; int i_length, r = 1;
const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; char psz_fullpath[4096], *psz_basename;
unsigned char buf[ISO_BLOCKSIZE]; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)];
CdioListNode_t* p_entnode; unsigned char buf[ISO_BLOCKSIZE];
iso9660_stat_t *p_statbuf; CdioListNode_t* p_entnode;
CdioList_t* p_entlist; iso9660_stat_t *p_statbuf;
size_t i; CdioList_t* p_entlist;
lsn_t lsn; size_t i;
int64_t i_file_length; lsn_t lsn;
int64_t i_file_length;
if ((p_iso == NULL) || (psz_path == NULL))
return 1; if ((p_iso == NULL) || (psz_path == NULL))
return 1;
i_length = snprintf(psz_fullpath, sizeof(psz_fullpath), "%s%s/", psz_extract_dir, psz_path);
if (i_length < 0) i_length = snprintf(psz_fullpath, sizeof(psz_fullpath), "%s%s/", psz_extract_dir, psz_path);
return 1; if (i_length < 0)
psz_basename = &psz_fullpath[i_length]; return 1;
psz_basename = &psz_fullpath[i_length];
p_entlist = iso9660_ifs_readdir(p_iso, psz_path);
if (!p_entlist) p_entlist = iso9660_ifs_readdir(p_iso, psz_path);
return 1; if (!p_entlist)
return 1;
_CDIO_LIST_FOREACH (p_entnode, p_entlist) {
p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); _CDIO_LIST_FOREACH (p_entnode, p_entlist) {
/* Eliminate . and .. entries */ p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode);
if ( (strcmp(p_statbuf->filename, ".") == 0) /* Eliminate . and .. entries */
|| (strcmp(p_statbuf->filename, "..") == 0) ) if ( (strcmp(p_statbuf->filename, ".") == 0)
continue; || (strcmp(p_statbuf->filename, "..") == 0) )
iso9660_name_translate(p_statbuf->filename, psz_basename); continue;
if (p_statbuf->type == _STAT_DIR) { iso9660_name_translate(p_statbuf->filename, psz_basename);
_mkdir(psz_fullpath); if (p_statbuf->type == _STAT_DIR) {
if (iso_extract_files(p_iso, psz_iso_name)) _mkdir(psz_fullpath);
goto out; if (iso_extract_files(p_iso, psz_iso_name))
} else { goto out;
printf("Extracting: %s\n", psz_fullpath); } else {
fd = fopen(psz_fullpath, "wb"); printf("Extracting: %s\n", psz_fullpath);
if (fd == NULL) { fd = fopen(psz_fullpath, "wb");
fprintf(stderr, " Unable to create file\n"); if (fd == NULL) {
goto out; fprintf(stderr, " Unable to create file\n");
} goto out;
i_file_length = p_statbuf->size; }
for (i = 0; i_file_length > 0; i++) { i_file_length = p_statbuf->size;
memset(buf, 0, ISO_BLOCKSIZE); for (i = 0; i_file_length > 0; i++) {
lsn = p_statbuf->lsn + i; memset(buf, 0, ISO_BLOCKSIZE);
if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { lsn = p_statbuf->lsn + i;
fprintf(stderr, " Error reading ISO9660 file %s at LSN %lu\n", if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) {
psz_iso_name, (long unsigned int)lsn); fprintf(stderr, " Error reading ISO9660 file %s at LSN %lu\n",
goto out; psz_iso_name, (long unsigned int)lsn);
} goto out;
fwrite(buf, (size_t)MIN(i_file_length, ISO_BLOCKSIZE), 1, fd); }
if (ferror(fd)) { fwrite(buf, (size_t)MIN(i_file_length, ISO_BLOCKSIZE), 1, fd);
fprintf(stderr, " Error writing file: %s\n", strerror(errno)); if (ferror(fd)) {
goto out; fprintf(stderr, " Error writing file %s: %s\n", psz_iso_name,
} strerror(errno));
i_file_length -= ISO_BLOCKSIZE; goto out;
} }
fclose(fd); i_file_length -= ISO_BLOCKSIZE;
fd = NULL; }
} fclose(fd);
} fd = NULL;
r = 0; }
}
out: r = 0;
if (fd != NULL)
fclose(fd); out:
_cdio_list_free(p_entlist, true); if (fd != NULL)
return r; fclose(fd);
} _cdio_list_free(p_entlist, true);
return r;
int main(int argc, char** argv) }
{
iso9660_t* p_iso = NULL; int main(int argc, char** argv)
udf_t* p_udf = NULL; {
udf_dirent_t* p_udf_root; iso9660_t* p_iso = NULL;
char *psz_str = NULL; udf_t* p_udf = NULL;
char vol_id[UDF_VOLID_SIZE] = ""; udf_dirent_t* p_udf_root;
char volset_id[UDF_VOLSET_ID_SIZE+1] = ""; char *psz_str = NULL;
int r = 0; char vol_id[UDF_VOLID_SIZE] = "";
char volset_id[UDF_VOLSET_ID_SIZE+1] = "";
cdio_loglevel_default = CDIO_LOG_DEBUG; int r = 0;
if (argc < 3) { cdio_loglevel_default = CDIO_LOG_DEBUG;
fprintf(stderr, "Usage: extract <iso_image> <extraction_dir>\n");
return 1; if (argc < 3) {
} fprintf(stderr, "Usage: extract <iso_image> <extraction_dir>\n");
return 1;
/* Warn if LFS doesn't appear to be enabled */ }
if (sizeof(off_t) < 8) {
fprintf(stderr, "INFO: Large File Support not detected (required for files >2GB)\n"); /* Warn if LFS doesn't appear to be enabled */
} if (sizeof(off_t) < 8) {
fprintf(stderr, "INFO: Large File Support not detected (required for files >2GB)\n");
psz_extract_dir = argv[2]; }
if (_mkdir(psz_extract_dir) == 0) {
printf("Creating directory: %s\n", psz_extract_dir); psz_extract_dir = argv[2];
} else if (errno != EEXIST) { if (_mkdir(psz_extract_dir) == 0) {
fprintf(stderr, "Unable to create extraction directory %s\n", psz_extract_dir); printf("Creating directory: %s\n", psz_extract_dir);
return 1; } else if (errno != EEXIST) {
} fprintf(stderr, "Unable to create extraction directory %s\n", psz_extract_dir);
return 1;
/* First try to open as UDF - fallback to ISO if it failed */ }
p_udf = udf_open(argv[1]);
if (p_udf == NULL) /* First try to open as UDF - fallback to ISO if it failed */
goto try_iso; p_udf = udf_open(argv[1]);
if (p_udf == NULL)
p_udf_root = udf_get_root(p_udf, true, 0); goto try_iso;
if (p_udf_root == NULL) {
fprintf(stderr, "Couldn't locate UDF root directory\n"); p_udf_root = udf_get_root(p_udf, true, 0);
goto out; if (p_udf_root == NULL) {
} fprintf(stderr, "Couldn't locate UDF root directory\n");
vol_id[0] = 0; volset_id[0] = 0; goto out;
}
/* Show basic UDF Volume info */ vol_id[0] = 0; volset_id[0] = 0;
if (udf_get_volume_id(p_udf, vol_id, sizeof(vol_id)) > 0)
fprintf(stderr, "Volume id: %s\n", vol_id); /* Show basic UDF Volume info */
if (udf_get_volume_id(p_udf, volset_id, sizeof(volset_id)) >0 ) { if (udf_get_volume_id(p_udf, vol_id, sizeof(vol_id)) > 0)
volset_id[UDF_VOLSET_ID_SIZE]='\0'; fprintf(stderr, "Volume id: %s\n", vol_id);
fprintf(stderr, "Volume set id: %s\n", volset_id); if (udf_get_volume_id(p_udf, volset_id, sizeof(volset_id)) >0 ) {
} volset_id[UDF_VOLSET_ID_SIZE]='\0';
fprintf(stderr, "Partition number: %d\n", udf_get_part_number(p_udf)); fprintf(stderr, "Volume set id: %s\n", volset_id);
}
/* Recursively extract files */ fprintf(stderr, "Partition number: %d\n", udf_get_part_number(p_udf));
r = udf_extract_files(p_udf, p_udf_root, "");
/* Recursively extract files */
goto out; r = udf_extract_files(p_udf, p_udf_root, "");
try_iso: goto out;
p_iso = iso9660_open(argv[1]);
if (p_iso == NULL) { try_iso:
fprintf(stderr, "Unable to open image '%s'.\n", argv[1]); p_iso = iso9660_open(argv[1]);
r = 1; if (p_iso == NULL) {
goto out; fprintf(stderr, "Unable to open image '%s'.\n", argv[1]);
} r = 1;
goto out;
/* Show basic ISO9660 info from the Primary Volume Descriptor. */ }
print_vd_info("Application", iso9660_ifs_get_application_id);
print_vd_info("Preparer ", iso9660_ifs_get_preparer_id); /* Show basic ISO9660 info from the Primary Volume Descriptor. */
print_vd_info("Publisher ", iso9660_ifs_get_publisher_id); print_vd_info("Application", iso9660_ifs_get_application_id);
print_vd_info("System ", iso9660_ifs_get_system_id); print_vd_info("Preparer ", iso9660_ifs_get_preparer_id);
print_vd_info("Volume ", iso9660_ifs_get_volume_id); print_vd_info("Publisher ", iso9660_ifs_get_publisher_id);
print_vd_info("Volume Set ", iso9660_ifs_get_volumeset_id); print_vd_info("System ", iso9660_ifs_get_system_id);
print_vd_info("Volume ", iso9660_ifs_get_volume_id);
r = iso_extract_files(p_iso, ""); print_vd_info("Volume Set ", iso9660_ifs_get_volumeset_id);
out: r = iso_extract_files(p_iso, "");
if (p_iso != NULL)
iso9660_close(p_iso); out:
if (p_udf != NULL) if (p_iso != NULL)
udf_close(p_udf); iso9660_close(p_iso);
if (p_udf != NULL)
return r; udf_close(p_udf);
}
return r;
}

View File

@@ -19,10 +19,10 @@
# #
cdio_config.h: $(top_builddir)/config.h cdio_config.h: $(top_builddir)/config.h
echo '#ifndef __CDIO_CONFIG_H__' > cdio_config.h @echo '#ifndef __CDIO_CONFIG_H__' > cdio_config.h
echo '#define __CDIO_CONFIG_H__' >> cdio_config.h @echo '#define __CDIO_CONFIG_H__' >> cdio_config.h
cat $(top_builddir)/config.h >>cdio_config.h @@SED@ -re 's/^(#[ \t]*define) /\1 CDIO_/' $(top_builddir)/config.h >>cdio_config.h
echo '#endif /* #ifndef CDIO_CONFIG_H */' >>cdio_config.h @echo '#endif /* #ifndef CDIO_CONFIG_H */' >>cdio_config.h
libcdioincludedir=$(includedir)/cdio libcdioincludedir=$(includedir)/cdio
dist_libcdioinclude_HEADERS = \ dist_libcdioinclude_HEADERS = \
@@ -30,7 +30,6 @@ dist_libcdioinclude_HEADERS = \
bytesex.h \ bytesex.h \
bytesex_asm.h \ bytesex_asm.h \
cdio.h \ cdio.h \
cdio_unconfig.h \
cd_types.h \ cd_types.h \
cdtext.h \ cdtext.h \
device.h \ device.h \