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 udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path) { HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; BOOL r, is_syslinux_cfg, is_old_c32[NB_OLD_C32]; int i_length; size_t i, nul_pos; char tmp[128], *psz_fullpath = NULL; const char* psz_basename; udf_dirent_t *p_udf_dirent2; uint8_t buf[UDF_BLOCKSIZE]; int64_t i_read, i_file_length; if ((p_udf_dirent == NULL) || (psz_path == NULL)) return 1; while ((p_udf_dirent = udf_readdir(p_udf_dirent)) != NULL) { if (FormatStatus) goto out; psz_basename = udf_get_filename(p_udf_dirent); if (strlen(psz_basename) == 0) continue; i_length = (int)(3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir) + 24); psz_fullpath = (char*)calloc(sizeof(char), i_length); if (psz_fullpath == NULL) { uprintf("Error allocating file name\n"); goto out; } i_length = _snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename); if (i_length < 0) { goto out; } if (udf_is_dir(p_udf_dirent)) { if (!scan_only) _mkdirU(psz_fullpath); p_udf_dirent2 = udf_opendir(p_udf_dirent); if (p_udf_dirent2 != NULL) { if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)])) goto out; } } else { i_file_length = udf_get_file_length(p_udf_dirent); if (check_iso_props(psz_path, &is_syslinux_cfg, is_old_c32, i_file_length, psz_basename, psz_fullpath)) { safe_free(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); // Remove the appended size for extraction 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); 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 while (i_file_length > 0) { if (FormatStatus) goto out; memset(buf, 0, UDF_BLOCKSIZE); i_read = udf_read_block(p_udf_dirent, buf, 1); if (i_read < 0) { uprintf(" Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]); goto out; } buf_size = (DWORD)MIN(i_file_length, i_read); for (i=0; i<WRITE_RETRIES; i++) { ISO_BLOCKING(r = WriteFile(file_handle, buf, buf_size, &wr_size, NULL)); if ((!r) || (buf_size != wr_size)) { uprintf(" Error writing file: %s", WindowsErrorString()); if (i < WRITE_RETRIES-1) uprintf(" RETRYING...\n"); } else { break; } } if (i >= WRITE_RETRIES) goto out; i_file_length -= i_read; 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); } } // If you have a fast USB 3.0 device, the default Windows buffering does an // excellent job at compensating for our small blocks read/writes to max out the // device's bandwidth. // The drawback however is with cancellation. With a large file, CloseHandle() // may take forever to complete and is not interruptible. We try to detect this. ISO_BLOCKING(safe_closehandle(file_handle)); if (is_syslinux_cfg) { // Workaround for isolinux config files requiring an ISO label for kernel // append that may be different from our USB label. 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); } } safe_free(psz_fullpath); } return 0; out: if (p_udf_dirent != NULL) udf_dirent_free(p_udf_dirent); ISO_BLOCKING(safe_closehandle(file_handle)); safe_free(psz_fullpath); return 1; }
static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path) { FILE *fd = NULL; int i_length; char* psz_fullpath; const char* psz_basename; udf_dirent_t *p_udf_dirent2; uint8_t buf[UDF_BLOCKSIZE]; int64_t i_read, i_file_length; if ((p_udf_dirent == NULL) || (psz_path == NULL)) return 1; while (udf_readdir(p_udf_dirent)) { psz_basename = udf_get_filename(p_udf_dirent); i_length = 3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir); psz_fullpath = (char*)calloc(sizeof(char), i_length); if (psz_fullpath == NULL) { fprintf(stderr, "Error allocating file name\n"); goto out; } i_length = snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename); if (i_length < 0) { goto out; } printf("-- Extracting: %s\n", psz_fullpath); if (udf_is_dir(p_udf_dirent)) { _mkdir(psz_fullpath); p_udf_dirent2 = udf_opendir(p_udf_dirent); if (p_udf_dirent2 != NULL) { if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)])) goto out; } } else { fd = fopen(psz_fullpath, "wb"); if (fd == NULL) { fprintf(stderr, " Unable to create file %s\n", psz_fullpath); goto out; } i_file_length = udf_get_file_length(p_udf_dirent); while (i_file_length > 0) { memset(buf, 0, UDF_BLOCKSIZE); i_read = udf_read_block(p_udf_dirent, buf, 1); if (i_read < 0) { fprintf(stderr, " Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]); goto out; } fwrite(buf, (size_t)MIN(i_file_length, i_read), 1, fd); if (ferror(fd)) { fprintf(stderr, " Error writing file %s: %s\n", psz_fullpath, strerror(errno)); goto out; } i_file_length -= i_read; } fclose(fd); fd = NULL; } free(psz_fullpath); } return 0; out: if (fd != NULL) fclose(fd); free(psz_fullpath); return 1; }
// Returns 0 on success, nonzero on error static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path) { HANDLE file_handle = NULL; DWORD buf_size, wr_size, err; EXTRACT_PROPS props; BOOL r, is_identical; int i_length; size_t i; char tmp[128], *psz_fullpath = NULL, *psz_sanpath = NULL; const char* psz_basename; udf_dirent_t *p_udf_dirent2; uint8_t buf[UDF_BLOCKSIZE]; int64_t i_read, i_file_length; if ((p_udf_dirent == NULL) || (psz_path == NULL)) return 1; while ((p_udf_dirent = udf_readdir(p_udf_dirent)) != NULL) { if (FormatStatus) goto out; psz_basename = udf_get_filename(p_udf_dirent); if (strlen(psz_basename) == 0) continue; i_length = (int)(3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir) + 24); psz_fullpath = (char*)calloc(sizeof(char), i_length); if (psz_fullpath == NULL) { uprintf("Error allocating file name\n"); goto out; } i_length = _snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename); if (i_length < 0) { goto out; } if (udf_is_dir(p_udf_dirent)) { if (!scan_only) { psz_sanpath = sanitize_filename(psz_fullpath, &is_identical); IGNORE_RETVAL(_mkdirU(psz_sanpath)); safe_free(psz_sanpath); } p_udf_dirent2 = udf_opendir(p_udf_dirent); if (p_udf_dirent2 != NULL) { if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)])) goto out; } } else { i_file_length = udf_get_file_length(p_udf_dirent); if (check_iso_props(psz_path, i_file_length, psz_basename, psz_fullpath, &props)) { safe_free(psz_fullpath); 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 (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; psz_sanpath = sanitize_filename(psz_fullpath, &is_identical); if (!is_identical) uprintf(" File name sanitized to '%s'\n", psz_sanpath); 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\n", WindowsErrorString()); if ((err == ERROR_ACCESS_DENIED) && (safe_strcmp(&psz_sanpath[3], autorun_name) == 0)) uprintf(stupid_antivirus); else goto out; } else while (i_file_length > 0) { if (FormatStatus) goto out; memset(buf, 0, UDF_BLOCKSIZE); i_read = udf_read_block(p_udf_dirent, buf, 1); if (i_read < 0) { uprintf(" Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]); goto out; } buf_size = (DWORD)MIN(i_file_length, i_read); for (i=0; i<WRITE_RETRIES; i++) { ISO_BLOCKING(r = WriteFile(file_handle, buf, buf_size, &wr_size, NULL)); if ((!r) || (buf_size != wr_size)) { uprintf(" Error writing file: %s", WindowsErrorString()); if (i < WRITE_RETRIES-1) uprintf(" RETRYING...\n"); } else { break; } } if (i >= WRITE_RETRIES) goto out; i_file_length -= i_read; if (nb_blocks++ % PROGRESS_THRESHOLD == 0) UpdateProgress(OP_DOS, 100.0f*nb_blocks/total_blocks); } // If you have a fast USB 3.0 device, the default Windows buffering does an // excellent job at compensating for our small blocks read/writes to max out the // device's bandwidth. // The drawback however is with cancellation. With a large file, CloseHandle() // may take forever to complete and is not interruptible. We try to detect this. 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); } safe_free(psz_fullpath); } return 0; out: if (p_udf_dirent != NULL) udf_dirent_free(p_udf_dirent); ISO_BLOCKING(safe_closehandle(file_handle)); safe_free(psz_fullpath); return 1; }
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[]) { udf_t *p_udf; FILE *p_outfd; char const *psz_udf_image; char const *psz_udf_fname; char const *psz_local_fname; if (argc > 1) psz_udf_image = argv[1]; else psz_udf_image = UDF_IMAGE; if (argc > 2) psz_udf_fname = argv[2]; else psz_udf_fname = UDF_FILENAME; if (argc > 3) psz_local_fname = argv[3]; else psz_local_fname = LOCAL_FILENAME; p_udf = udf_open (psz_udf_image); if (NULL == p_udf) { fprintf(stderr, "Sorry, couldn't open %s as something using UDF\n", psz_udf_image); return 1; } else { udf_dirent_t *p_udf_root = udf_get_root(p_udf, true, 0); udf_dirent_t *p_udf_file = NULL; if (NULL == p_udf_root) { fprintf(stderr, "Sorry, couldn't find / in %s\n", psz_udf_image); return 1; } p_udf_file = udf_fopen(p_udf_root, psz_udf_fname); if (!p_udf_file) { fprintf(stderr, "Sorry, couldn't find %s in %s\n", psz_udf_fname, psz_udf_image); return 2; } if (!(p_outfd = fopen (psz_local_fname, "wb"))) { perror ("fopen()"); return 3; } { uint64_t i_file_length = udf_get_file_length(p_udf_file); const unsigned int i_blocks = (unsigned int) CEILING(i_file_length, UDF_BLOCKSIZE); unsigned int i; for (i = 0; i < i_blocks ; i++) { char buf[UDF_BLOCKSIZE] = {'\0',}; ssize_t i_read = udf_read_block(p_udf_file, buf, 1); if ( i_read < 0 ) { fprintf(stderr, "Error reading UDF file %s at block %u\n", psz_local_fname, i); return 4; } fwrite (buf, i_read, 1, p_outfd); if (ferror (p_outfd)) { perror ("fwrite()"); return 5; } } fflush (p_outfd); udf_dirent_free(p_udf_root); udf_close(p_udf); /* Make sure the file size has the exact same byte size. Without the truncate below, the file will a multiple of UDF_BLOCKSIZE. */ if (ftruncate (fileno (p_outfd), i_file_length)) perror ("ftruncate()"); printf("Extraction of file '%s' from %s successful.\n", psz_local_fname, psz_udf_image); return 0; } } }