/*! Read pathname (a directory) and return a list of iso9660_stat_t of the files inside that. The caller must free the returned result. */ CdioList_t * iso9660_ifs_readdir (iso9660_t *p_iso, const char pathname[]) { iso9660_stat_t *p_stat; if (!p_iso) return NULL; if (!pathname) return NULL; p_stat = iso9660_ifs_stat (p_iso, pathname); if (!p_stat) return NULL; if (p_stat->type != _STAT_DIR) { free(p_stat); return NULL; } { long int ret; unsigned offset = 0; uint8_t *_dirbuf = NULL; CdioList_t *retval = _cdio_list_new (); if (p_stat->size != ISO_BLOCKSIZE * p_stat->secsize) { cdio_warn ("bad size for ISO9660 directory (%ud) should be (%lu)!", (unsigned int) p_stat->size, (unsigned long int) ISO_BLOCKSIZE * p_stat->secsize); } _dirbuf = _cdio_malloc (p_stat->secsize * ISO_BLOCKSIZE); ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize); if (ret != ISO_BLOCKSIZE*p_stat->secsize) return NULL; while (offset < (p_stat->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_iso9660_stat; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_iso9660_stat = _iso9660_dir_to_statbuf(p_iso9660_dir, true, p_iso->i_joliet_level); _cdio_list_append (retval, p_iso9660_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (p_stat->secsize * ISO_BLOCKSIZE)); free (_dirbuf); free (p_stat); return retval; } }
/*! Read the Primary Volume Descriptor for an ISO 9660 image. True is returned if read, and false if there was an error. */ bool iso9660_ifs_read_pvd (const iso9660_t *p_iso, /*out*/ iso9660_pvd_t *p_pvd) { if (0 == iso9660_iso_seek_read (p_iso, p_pvd, ISO_PVD_SECTOR, 1)) { cdio_warn ("error reading PVD sector (%d)", ISO_PVD_SECTOR); return false; } return check_pvd(p_pvd); }
/*! Read the Primary Volume Descriptor for an ISO 9660 image. True is returned if read, and false if there was an error. */ static bool iso9660_ifs_read_pvd_loglevel (const iso9660_t *p_iso, /*out*/ iso9660_pvd_t *p_pvd, cdio_log_level_t log_level) { if (0 == iso9660_iso_seek_read (p_iso, p_pvd, ISO_PVD_SECTOR, 1)) { cdio_log ( log_level, "error reading PVD sector (%d)", ISO_PVD_SECTOR ); return false; } return check_pvd(p_pvd, log_level); }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_ifs_read_superblock (iso9660_t *p_iso, iso_extension_mask_t iso_extension_mask) { iso9660_svd_t p_svd; /* Secondary volume descriptor. */ int i; if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd))) return false; p_iso->u_joliet_level = 0; /* There may be multiple Secondary Volume Descriptors (eg. El Torito + Joliet) */ for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) { if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */ break; if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) { /* We're only interested in Joliet => make sure the SVD isn't overwritten */ if (p_iso->u_joliet_level == 0) memcpy(&(p_iso->svd), &p_svd, sizeof(iso9660_svd_t)); if (p_svd.escape_sequences[0] == 0x25 && p_svd.escape_sequences[1] == 0x2f) { switch (p_svd.escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_iso->u_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_iso->u_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_iso->u_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_iso->u_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_iso->u_joliet_level); } } } } return true; }
/*! Read the Super block of an ISO 9660 image. This is the Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume Descriptor if (Joliet) extensions are acceptable. */ bool iso9660_ifs_read_superblock (iso9660_t *p_iso, iso_extension_mask_t iso_extension_mask) { iso9660_svd_t *p_svd; /* Secondary volume descriptor. */ if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd))) return false; p_svd = &(p_iso->svd); p_iso->i_joliet_level = 0; if (0 != iso9660_iso_seek_read (p_iso, p_svd, ISO_PVD_SECTOR+1, 1)) { if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd->type) ) { if (p_svd->escape_sequences[0] == 0x25 && p_svd->escape_sequences[1] == 0x2f) { switch (p_svd->escape_sequences[2]) { case 0x40: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL1) p_iso->i_joliet_level = 1; break; case 0x43: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL2) p_iso->i_joliet_level = 2; break; case 0x45: if (iso_extension_mask & ISO_EXTENSION_JOLIET_LEVEL3) p_iso->i_joliet_level = 3; break; default: cdio_info("Supplementary Volume Descriptor found, but not Joliet"); } if (p_iso->i_joliet_level > 0) { cdio_info("Found Extension: Joliet Level %d", p_iso->i_joliet_level); } } } } return true; }
int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file) { size_t i; ssize_t read_size; int64_t file_length, r = 0; char buf[UDF_BLOCKSIZE]; DWORD buf_size, wr_size; BOOL s; iso9660_t* p_iso = NULL; udf_t* p_udf = NULL; udf_dirent_t *p_udf_root = NULL, *p_udf_file = NULL; iso9660_stat_t *p_statbuf = NULL; lsn_t lsn; HANDLE file_handle = INVALID_HANDLE_VALUE; file_handle = CreateFileU(dest_file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { uprintf(" Unable to create file %s: %s\n", dest_file, WindowsErrorString()); goto out; } /* First try to open as UDF - fallback to ISO if it failed */ p_udf = udf_open(iso); if (p_udf == NULL) goto try_iso; p_udf_root = udf_get_root(p_udf, true, 0); if (p_udf_root == NULL) { uprintf("Couldn't locate UDF root directory\n"); goto out; } p_udf_file = udf_fopen(p_udf_root, iso_file); if (!p_udf_file) { uprintf("Couldn't locate file %s in ISO image\n", iso_file); goto out; } file_length = udf_get_file_length(p_udf_file); while (file_length > 0) { memset(buf, 0, UDF_BLOCKSIZE); read_size = udf_read_block(p_udf_file, buf, 1); if (read_size < 0) { uprintf("Error reading UDF file %s\n", iso_file); goto out; } buf_size = (DWORD)MIN(file_length, read_size); s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL); if ((!s) || (buf_size != wr_size)) { uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); goto out; } file_length -= read_size; r += read_size; } goto out; try_iso: p_iso = iso9660_open(iso); if (p_iso == NULL) { uprintf("Unable to open image '%s'.\n", iso); goto out; } p_statbuf = iso9660_ifs_stat_translate(p_iso, iso_file); if (p_statbuf == NULL) { uprintf("Could not get ISO-9660 file information for file %s\n", iso_file); goto out; } file_length = p_statbuf->size; for (i = 0; file_length > 0; i++) { memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + (lsn_t)i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { uprintf(" Error reading ISO9660 file %s at LSN %lu\n", iso_file, (long unsigned int)lsn); goto out; } buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE); s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL); if ((!s) || (buf_size != wr_size)) { uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); goto out; } file_length -= ISO_BLOCKSIZE; r += ISO_BLOCKSIZE; } out: safe_closehandle(file_handle); if (p_statbuf != NULL) safe_free(p_statbuf->rr.psz_symlink); safe_free(p_statbuf); if (p_udf_root != NULL) udf_dirent_free(p_udf_root); if (p_udf_file != NULL) udf_dirent_free(p_udf_file); if (p_iso != NULL) iso9660_close(p_iso); if (p_udf != NULL) udf_close(p_udf); return r; }
// Returns 0 on success, nonzero on error static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) { HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; BOOL s, is_syslinux_cfg, is_old_c32[NB_OLD_C32], is_symlink; int i_length, r = 1; char tmp[128], psz_fullpath[1024], *psz_basename; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; unsigned char buf[ISO_BLOCKSIZE]; CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioList_t* p_entlist; size_t i, j, nul_pos; lsn_t lsn; int64_t i_file_length; 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) return 1; psz_basename = &psz_fullpath[i_length]; p_entlist = iso9660_ifs_readdir(p_iso, psz_path); if (!p_entlist) { uprintf("Could not access directory %s\n", psz_path); return 1; } _CDIO_LIST_FOREACH(p_entnode, p_entlist) { if (FormatStatus) goto out; p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); // Eliminate . and .. entries if ( (strcmp(p_statbuf->filename, ".") == 0) || (strcmp(p_statbuf->filename, "..") == 0) ) continue; // Rock Ridge requires an exception is_symlink = FALSE; if ((p_statbuf->rr.b3_rock == yep) && enable_rockridge) { safe_strcpy(psz_basename, sizeof(psz_fullpath)-i_length-1, p_statbuf->filename); if (safe_strlen(p_statbuf->filename) > 64) iso_report.has_long_filename = TRUE; // libcdio has a memleak for Rock Ridge symlinks. It doesn't look like there's an easy fix there as // a generic list that's unaware of RR extensions is being used, so we prevent that memleak ourselves is_symlink = (p_statbuf->rr.psz_symlink != NULL); if (is_symlink) iso_report.has_symlinks = TRUE; if (scan_only) safe_free(p_statbuf->rr.psz_symlink); } else { iso9660_name_translate_ext(p_statbuf->filename, psz_basename, i_joliet_level); } if (p_statbuf->type == _STAT_DIR) { if (!scan_only) _mkdirU(psz_fullpath); if (iso_extract_files(p_iso, psz_iso_name)) goto out; } else { i_file_length = p_statbuf->size; if (check_iso_props(psz_path, &is_syslinux_cfg, is_old_c32, i_file_length, psz_basename, psz_fullpath)) { continue; } // Replace slashes with backslashes and append the size to the path for UI display nul_pos = safe_strlen(psz_fullpath); for (i=0; i<nul_pos; i++) if (psz_fullpath[i] == '/') psz_fullpath[i] = '\\'; safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, TRUE, FALSE)); uprintf("Extracting: %s\n", psz_fullpath); safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, FALSE, FALSE)); SetWindowTextU(hISOFileName, psz_fullpath); // ISO9660 cannot handle backslashes for (i=0; i<nul_pos; i++) if (psz_fullpath[i] == '\\') psz_fullpath[i] = '/'; psz_fullpath[nul_pos] = 0; for (i=0; i<NB_OLD_C32; i++) { if (is_old_c32[i] && use_own_c32[i]) { static_sprintf(tmp, "%s/syslinux-%s/%s", FILES_DIR, embedded_sl_version_str[0], old_c32_name[i]); if (CopyFileA(tmp, psz_fullpath, FALSE)) { uprintf(" Replaced with local version\n"); break; } uprintf(" Could not replace file: %s\n", WindowsErrorString()); } } if (i < NB_OLD_C32) continue; if (sanitize_filename(psz_fullpath)) uprintf(" File name sanitized to '%s'\n", psz_fullpath); if (is_symlink) { if (i_file_length == 0) uprintf(" Ignoring Rock Ridge symbolic link to '%s'\n", p_statbuf->rr.psz_symlink); safe_free(p_statbuf->rr.psz_symlink); } file_handle = CreateFileU(psz_fullpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { err = GetLastError(); uprintf(" Unable to create file: %s\n", WindowsErrorString()); if ((err == ERROR_ACCESS_DENIED) && (safe_strcmp(&psz_fullpath[3], autorun_name) == 0)) uprintf(stupid_antivirus); else goto out; } else for (i=0; i_file_length>0; i++) { if (FormatStatus) goto out; memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + (lsn_t)i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { uprintf(" Error reading ISO9660 file %s at LSN %lu\n", psz_iso_name, (long unsigned int)lsn); goto out; } buf_size = (DWORD)MIN(i_file_length, ISO_BLOCKSIZE); for (j=0; j<WRITE_RETRIES; j++) { ISO_BLOCKING(s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL)); if ((!s) || (buf_size != wr_size)) { uprintf(" Error writing file: %s", WindowsErrorString()); if (j < WRITE_RETRIES-1) uprintf(" RETRYING...\n"); } else { break; } } if (j >= WRITE_RETRIES) goto out; i_file_length -= ISO_BLOCKSIZE; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) { SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)((MAX_PROGRESS*nb_blocks)/total_blocks), 0); UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); } } ISO_BLOCKING(safe_closehandle(file_handle)); if (is_syslinux_cfg) { if (replace_in_token_data(psz_fullpath, "append", iso_report.label, iso_report.usb_label, TRUE) != NULL) uprintf("Patched %s: '%s' -> '%s'\n", psz_fullpath, iso_report.label, iso_report.usb_label); } } } r = 0; out: ISO_BLOCKING(safe_closehandle(file_handle)); _cdio_list_free(p_entlist, true); return r; }
static iso9660_stat_t * _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root, char **splitpath) { unsigned offset = 0; uint8_t *_dirbuf = NULL; int ret; if (!splitpath[0]) { iso9660_stat_t *p_stat; unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1; p_stat = calloc(1, len); if (!p_stat) { cdio_warn("Couldn't calloc(1, %d)", len); return NULL; } memcpy(p_stat, _root, len); p_stat->rr.psz_symlink = calloc(1, p_stat->rr.i_symlink_max); memcpy(p_stat->rr.psz_symlink, _root->rr.psz_symlink, p_stat->rr.i_symlink_max); return p_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 = calloc(1, _root->secsize * ISO_BLOCKSIZE); if (!_dirbuf) { cdio_warn("Couldn't calloc(1, %d)", _root->secsize * ISO_BLOCKSIZE); return NULL; } ret = iso9660_iso_seek_read (p_iso, _dirbuf, _root->lsn, _root->secsize); if (ret!=ISO_BLOCKSIZE*_root->secsize) return NULL; while (offset < (_root->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_stat; int cmp; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, p_iso->b_xa, p_iso->i_joliet_level); cmp = strcmp(splitpath[0], p_stat->filename); if ( 0 != cmp && 0 == p_iso->i_joliet_level && yep != p_stat->rr.b3_rock ) { char *trans_fname = NULL; unsigned int i_trans_fname=strlen(p_stat->filename); int trans_len; if (i_trans_fname) { trans_fname = calloc(1, i_trans_fname+1); if (!trans_fname) { cdio_warn("can't allocate %lu bytes", (long unsigned int) strlen(p_stat->filename)); return NULL; } trans_len = iso9660_name_translate_ext(p_stat->filename, trans_fname, p_iso->i_joliet_level); cmp = strcmp(splitpath[0], trans_fname); free(trans_fname); } } if (!cmp) { iso9660_stat_t *ret_stat = _fs_iso_stat_traverse (p_iso, p_stat, &splitpath[1]); free(p_stat->rr.psz_symlink); free(p_stat); free (_dirbuf); return ret_stat; } free(p_stat->rr.psz_symlink); free(p_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); /* not found */ free (_dirbuf); return NULL; }
/*! Read psz_path (a directory) and return a list of iso9660_stat_t of the files inside that. The caller must free the returned result. */ CdioList_t * iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[]) { iso9660_stat_t *p_stat; if (!p_iso) return NULL; if (!psz_path) return NULL; p_stat = iso9660_ifs_stat (p_iso, psz_path); if (!p_stat) return NULL; if (p_stat->type != _STAT_DIR) { free(p_stat->rr.psz_symlink); free(p_stat); return NULL; } { long int ret; unsigned offset = 0; uint8_t *_dirbuf = NULL; CdioList_t *retval = _cdio_list_new (); _dirbuf = calloc(1, p_stat->secsize * ISO_BLOCKSIZE); if (!_dirbuf) { cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE); return NULL; } ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize); if (ret != ISO_BLOCKSIZE*p_stat->secsize) { free (_dirbuf); return NULL; } while (offset < (p_stat->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_iso9660_stat; if (!iso9660_get_dir_len(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); offset += iso9660_get_dir_len(p_iso9660_dir); } free (_dirbuf); if (offset != (p_stat->secsize * ISO_BLOCKSIZE)) { free (p_stat); _cdio_list_free (retval, true); return NULL; } free (p_stat->rr.psz_symlink); free (p_stat); return retval; } }
static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) { FILE *fd = NULL; int i_length, r = 1; char psz_fullpath[4096], *psz_basename; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; unsigned char buf[ISO_BLOCKSIZE]; CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioList_t* p_entlist; size_t i; lsn_t lsn; int64_t i_file_length; 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) return 1; psz_basename = &psz_fullpath[i_length]; p_entlist = iso9660_ifs_readdir(p_iso, psz_path); if (!p_entlist) { printf("Could not access %s\n", psz_path); return 1; } _CDIO_LIST_FOREACH (p_entnode, p_entlist) { p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); /* Eliminate . and .. entries */ if ( (strcmp(p_statbuf->filename, ".") == 0) || (strcmp(p_statbuf->filename, "..") == 0) ) continue; iso9660_name_translate_ext(p_statbuf->filename, psz_basename, i_joliet_level); if (p_statbuf->type == _STAT_DIR) { _mkdir(psz_fullpath); if (iso_extract_files(p_iso, psz_iso_name)) goto out; } else { printf("Extracting: %s\n", psz_fullpath); fd = fopen(psz_fullpath, "wb"); if (fd == NULL) { fprintf(stderr, " Unable to create file\n"); goto out; } i_file_length = p_statbuf->size; for (i = 0; i_file_length > 0; i++) { memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { fprintf(stderr, " Error reading ISO9660 file %s at LSN %lu\n", psz_iso_name, (long unsigned int)lsn); goto out; } 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)); goto out; } i_file_length -= ISO_BLOCKSIZE; } fclose(fd); fd = NULL; } }
int main(int argc, const char *argv[]) { iso9660_stat_t *p_statbuf; FILE *p_outfd; int i; iso9660_t *p_iso = iso9660_open (ISO9660_IMAGE); if (NULL == p_iso) { fprintf(stderr, "Sorry, couldn't open ISO 9660 image %s\n", ISO9660_IMAGE); return 1; } p_statbuf = iso9660_ifs_stat_translate (p_iso, LOCAL_FILENAME); if (NULL == p_statbuf) { fprintf(stderr, "Could not get ISO-9660 file information for file %s\n", LOCAL_FILENAME); iso9660_close(p_iso); return 2; } if (!(p_outfd = fopen (LOCAL_FILENAME, "wb"))) { perror ("fopen()"); free(p_statbuf); iso9660_close(p_iso); return 3; } /* Copy the blocks from the ISO-9660 filesystem to the local filesystem. */ for (i = 0; i < p_statbuf->size; i += ISO_BLOCKSIZE) { char buf[ISO_BLOCKSIZE]; memset (buf, 0, ISO_BLOCKSIZE); if ( ISO_BLOCKSIZE != iso9660_iso_seek_read (p_iso, buf, p_statbuf->lsn + (i / ISO_BLOCKSIZE), 1) ) { fprintf(stderr, "Error reading ISO 9660 file at lsn %lu\n", (long unsigned int) p_statbuf->lsn + (i / ISO_BLOCKSIZE)); my_exit(4); } fwrite (buf, ISO_BLOCKSIZE, 1, p_outfd); 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)) perror ("ftruncate()"); printf("Extraction of file 'copying' from %s successful.\n", ISO9660_IMAGE); my_exit(0); }
// Returns 0 on success, nonzero on error static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) { HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; BOOL is_symlink, is_identical; int i_length, r = 1; char tmp[128], psz_fullpath[MAX_PATH], *psz_basename, *psz_sanpath; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; unsigned char buf[ISO_BLOCKSIZE]; CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioList_t* p_entlist; size_t i; lsn_t lsn; int64_t i_file_length; 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) return 1; psz_basename = &psz_fullpath[i_length]; p_entlist = iso9660_ifs_readdir(p_iso, psz_path); if (!p_entlist) { uprintf("Could not access directory %s", psz_path); return 1; } _CDIO_LIST_FOREACH(p_entnode, p_entlist) { if (FormatStatus) goto out; p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); // Eliminate . and .. entries if ( (strcmp(p_statbuf->filename, ".") == 0) || (strcmp(p_statbuf->filename, "..") == 0) ) continue; // Rock Ridge requires an exception is_symlink = FALSE; if ((p_statbuf->rr.b3_rock == yep) && enable_rockridge) { safe_strcpy(psz_basename, sizeof(psz_fullpath)-i_length-1, p_statbuf->filename); if (safe_strlen(p_statbuf->filename) > 64) img_report.has_long_filename = TRUE; // libcdio has a memleak for Rock Ridge symlinks. It doesn't look like there's an easy fix there as // a generic list that's unaware of RR extensions is being used, so we prevent that memleak ourselves is_symlink = (p_statbuf->rr.psz_symlink != NULL); if (is_symlink) img_report.has_symlinks = TRUE; if (scan_only) safe_free(p_statbuf->rr.psz_symlink); } else { iso9660_name_translate_ext(p_statbuf->filename, psz_basename, i_joliet_level); } if (p_statbuf->type == _STAT_DIR) { if (!scan_only) { psz_sanpath = sanitize_filename(psz_fullpath, &is_identical); IGNORE_RETVAL(_mkdirU(psz_sanpath)); if (preserve_timestamps) { LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm)); set_directory_timestamp(psz_sanpath, ft, ft, ft); } safe_free(psz_sanpath); } if (iso_extract_files(p_iso, psz_iso_name)) goto out; } else { i_file_length = p_statbuf->size; if (check_iso_props(psz_path, i_file_length, psz_basename, psz_fullpath, &props)) { continue; } print_extracted_file(psz_fullpath, i_file_length); for (i=0; i<NB_OLD_C32; i++) { if (props.is_old_c32[i] && use_own_c32[i]) { static_sprintf(tmp, "%s/syslinux-%s/%s", FILES_DIR, embedded_sl_version_str[0], old_c32_name[i]); if (CopyFileU(tmp, psz_fullpath, FALSE)) { uprintf(" Replaced with local version %s", IsFileInDB(tmp)?"✓":"✗"); break; } uprintf(" Could not replace file: %s", WindowsErrorString()); } } if (i < NB_OLD_C32) continue; psz_sanpath = sanitize_filename(psz_fullpath, &is_identical); if (!is_identical) uprintf(" File name sanitized to '%s'", psz_sanpath); if (is_symlink) { if (i_file_length == 0) uprintf(" Ignoring Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink); safe_free(p_statbuf->rr.psz_symlink); } file_handle = CreateFileU(psz_sanpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { err = GetLastError(); uprintf(" Unable to create file: %s", WindowsErrorString()); if ((err == ERROR_ACCESS_DENIED) && (safe_strcmp(&psz_sanpath[3], autorun_name) == 0)) uprintf(stupid_antivirus); else goto out; } else for (i=0; i_file_length>0; i++) { if (FormatStatus) goto out; memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + (lsn_t)i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { uprintf(" Error reading ISO9660 file %s at LSN %lu", psz_iso_name, (long unsigned int)lsn); goto out; } buf_size = (DWORD)MIN(i_file_length, ISO_BLOCKSIZE); ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)); if (!r) { uprintf(" Error writing file: %s", WindowsErrorString()); goto out; } i_file_length -= ISO_BLOCKSIZE; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); } if (preserve_timestamps) { LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm)); if (!SetFileTime(file_handle, ft, ft, ft)) uprintf(" Could not set timestamp: %s", WindowsErrorString()); } ISO_BLOCKING(safe_closehandle(file_handle)); if (props.is_syslinux_cfg || props.is_grub_cfg) fix_config(psz_sanpath, psz_path, psz_basename, &props); safe_free(psz_sanpath); } } r = 0; out: ISO_BLOCKING(safe_closehandle(file_handle)); _cdio_list_free(p_entlist, true); return r; }
uint32_t GetInstallWimVersion(const char* iso) { char *wim_path = NULL, *p, buf[UDF_BLOCKSIZE] = { 0 }; uint32_t* wim_header = (uint32_t*)buf, r = 0xffffffff; iso9660_t* p_iso = NULL; udf_t* p_udf = NULL; udf_dirent_t *p_udf_root = NULL, *p_udf_file = NULL; iso9660_stat_t *p_statbuf = NULL; wim_path = safe_strdup(&img_report.install_wim_path[2]); if (wim_path == NULL) goto out; // UDF indiscriminately accepts slash or backslash delimiters, // but ISO-9660 requires slash for (p = wim_path; *p != 0; p++) if (*p == '\\') *p = '/'; // First try to open as UDF - fallback to ISO if it failed p_udf = udf_open(iso); if (p_udf == NULL) goto try_iso; p_udf_root = udf_get_root(p_udf, true, 0); if (p_udf_root == NULL) { uprintf("Could not locate UDF root directory\n"); goto out; } p_udf_file = udf_fopen(p_udf_root, wim_path); if (!p_udf_file) { uprintf("Could not locate file %s in ISO image\n", wim_path); goto out; } if (udf_read_block(p_udf_file, buf, 1) != UDF_BLOCKSIZE) { uprintf("Error reading UDF file %s\n", wim_path); goto out; } r = wim_header[3]; goto out; try_iso: p_iso = iso9660_open(iso); if (p_iso == NULL) { uprintf("Unable to open image '%s'.\n", iso); goto out; } p_statbuf = iso9660_ifs_stat_translate(p_iso, wim_path); if (p_statbuf == NULL) { uprintf("Could not get ISO-9660 file information for file %s\n", wim_path); goto out; } if (iso9660_iso_seek_read(p_iso, buf, p_statbuf->lsn, 1) != ISO_BLOCKSIZE) { uprintf("Error reading ISO9660 file %s at LSN %lu\n", wim_path, (long unsigned int)p_statbuf->lsn); goto out; } r = wim_header[3]; out: if (p_statbuf != NULL) safe_free(p_statbuf->rr.psz_symlink); safe_free(p_statbuf); if (p_udf_root != NULL) udf_dirent_free(p_udf_root); if (p_udf_file != NULL) udf_dirent_free(p_udf_file); if (p_iso != NULL) iso9660_close(p_iso); if (p_udf != NULL) udf_close(p_udf); safe_free(wim_path); return bswap_uint32(r); }
int main(int argc, const char *argv[]) { iso9660_stat_t *p_statbuf; FILE *p_outfd; int i; char const *psz_image; char const *psz_fname; iso9660_t *p_iso; if (argc > 3) { printf("usage %s [ISO9660-image.ISO [filename]]\n", argv[0]); printf("Extracts filename from ISO-9660-image.ISO\n"); return 1; } if (argc > 1) psz_image = argv[1]; else psz_image = ISO9660_IMAGE; if (argc > 2) psz_fname = argv[2]; else psz_fname = LOCAL_FILENAME; p_iso = iso9660_open (psz_image); if (NULL == p_iso) { fprintf(stderr, "Sorry, couldn't open ISO 9660 image %s\n", psz_image); return 1; } p_statbuf = iso9660_ifs_stat_translate (p_iso, psz_fname); if (NULL == p_statbuf) { fprintf(stderr, "Could not get ISO-9660 file information for file %s\n", psz_fname); iso9660_close(p_iso); return 2; } if (!(p_outfd = fopen (psz_fname, "wb"))) { perror ("fopen()"); free(p_statbuf); iso9660_close(p_iso); return 3; } /* 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++) { 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); } } } 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)) perror ("ftruncate()"); printf("Extraction of file '%s' from %s successful.\n", psz_fname, psz_image); my_exit(0); }
static iso9660_stat_t * _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root, char **splitpath, bool translate) { unsigned offset = 0; uint8_t *_dirbuf = NULL; int ret; if (!splitpath[0]) { iso9660_stat_t *p_stat; unsigned int len=sizeof(iso9660_stat_t) + strlen(_root->filename)+1; p_stat = _cdio_malloc(len); memcpy(p_stat, _root, len); return p_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 (p_iso, _dirbuf, _root->lsn, _root->secsize); if (ret!=ISO_BLOCKSIZE*_root->secsize) return NULL; while (offset < (_root->secsize * ISO_BLOCKSIZE)) { iso9660_dir_t *p_iso9660_dir = (void *) &_dirbuf[offset]; iso9660_stat_t *p_stat; int cmp; if (!iso9660_get_dir_len(p_iso9660_dir)) { offset++; continue; } p_stat = _iso9660_dir_to_statbuf (p_iso9660_dir, true, p_iso->i_joliet_level); if (translate) { char *trans_fname = malloc(strlen(p_stat->filename)+1); int trans_len; if (trans_fname == NULL) { cdio_warn("can't allocate %lu bytes", (long unsigned int) strlen(p_stat->filename)); return NULL; } trans_len = iso9660_name_translate_ext(p_stat->filename, trans_fname, p_iso->i_joliet_level); cmp = strcmp(splitpath[0], trans_fname); free(trans_fname); } else { cmp = strcmp(splitpath[0], p_stat->filename); } if (!cmp) { iso9660_stat_t *ret_stat = _fs_iso_stat_traverse (p_iso, p_stat, &splitpath[1], translate); free(p_stat); free (_dirbuf); return ret_stat; } free(p_stat); offset += iso9660_get_dir_len(p_iso9660_dir); } cdio_assert (offset == (_root->secsize * ISO_BLOCKSIZE)); /* not found */ free (_dirbuf); return NULL; }
// Returns 0 on success, nonzero on error static int iso_extract_files(iso9660_t* p_iso, const char *psz_path) { HANDLE file_handle = NULL; DWORD buf_size, wr_size; BOOL s, is_syslinux_cfg, is_old_vesamenu; int i_length, r = 1; char psz_fullpath[1024], *psz_basename; const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)]; unsigned char buf[ISO_BLOCKSIZE]; CdioListNode_t* p_entnode; iso9660_stat_t *p_statbuf; CdioList_t* p_entlist; size_t i, nul_pos; lsn_t lsn; int64_t i_file_length; if ((p_iso == NULL) || (psz_path == NULL)) return 1; i_length = safe_sprintf(psz_fullpath, sizeof(psz_fullpath), "%s%s/", psz_extract_dir, psz_path); if (i_length < 0) return 1; psz_basename = &psz_fullpath[i_length]; p_entlist = iso9660_ifs_readdir(p_iso, psz_path); if (!p_entlist) { uprintf("Could not access directory %s\n", psz_path); return 1; } _CDIO_LIST_FOREACH(p_entnode, p_entlist) { if (FormatStatus) goto out; p_statbuf = (iso9660_stat_t*) _cdio_list_node_data(p_entnode); /* Eliminate . and .. entries */ if ( (strcmp(p_statbuf->filename, ".") == 0) || (strcmp(p_statbuf->filename, "..") == 0) ) continue; iso9660_name_translate_ext(p_statbuf->filename, psz_basename, i_joliet_level); if (p_statbuf->type == _STAT_DIR) { if (!scan_only) _mkdirU(psz_fullpath); if (iso_extract_files(p_iso, psz_iso_name)) goto out; } else { i_file_length = p_statbuf->size; if (check_iso_props(psz_path, &is_syslinux_cfg, &is_old_vesamenu, i_file_length, psz_basename, psz_fullpath)) { continue; } // Replace slashes with backslashes and append the size to the path for UI display nul_pos = safe_strlen(psz_fullpath); for (i=0; i<nul_pos; i++) if (psz_fullpath[i] == '/') psz_fullpath[i] = '\\'; safe_strcpy(&psz_fullpath[nul_pos], 24, size_to_hr(i_file_length)); uprintf("Extracting: %s\n", psz_fullpath); SetWindowTextU(hISOFileName, psz_fullpath); // ISO9660 cannot handle backslashes for (i=0; i<nul_pos; i++) if (psz_fullpath[i] == '\\') psz_fullpath[i] = '/'; psz_fullpath[nul_pos] = 0; if (is_old_vesamenu && use_own_vesamenu) { if (CopyFileA("vesamenu.c32", psz_fullpath, FALSE)) { uprintf(" Replaced with local version\n"); continue; } uprintf(" Could not replace file: %s\n", WindowsErrorString()); } file_handle = CreateFileU(psz_fullpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_handle == INVALID_HANDLE_VALUE) { uprintf(" Unable to create file: %s\n", WindowsErrorString()); goto out; } for (i = 0; i_file_length > 0; i++) { if (FormatStatus) goto out; memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + (lsn_t)i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { uprintf(" Error reading ISO9660 file %s at LSN %lu\n", psz_iso_name, (long unsigned int)lsn); goto out; } buf_size = (DWORD)MIN(i_file_length, ISO_BLOCKSIZE); ISO_BLOCKING(s = WriteFile(file_handle, buf, buf_size, &wr_size, NULL)); if ((!s) || (buf_size != wr_size)) { uprintf(" Error writing file: %s\n", WindowsErrorString()); goto out; } i_file_length -= ISO_BLOCKSIZE; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) { SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)((MAX_PROGRESS*nb_blocks)/total_blocks), 0); UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); } } ISO_BLOCKING(safe_closehandle(file_handle)); if (is_syslinux_cfg) { if (replace_in_token_data(psz_fullpath, "append", iso_report.label, iso_report.usb_label, TRUE) != NULL) uprintf("Patched %s: '%s' -> '%s'\n", psz_fullpath, iso_report.label, iso_report.usb_label); } } } r = 0; out: ISO_BLOCKING(safe_closehandle(file_handle)); _cdio_list_free(p_entlist, true); return r; }