From 64e88489ee47f4e5dca458970688485a0a165c30 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Feb 2019 00:26:25 +0100 Subject: Allow .ipsw files or extracted IPSW as source --- configure.ac | 5 +- src/common.c | 21 ++- src/common.h | 6 +- src/idevicerestore.c | 74 +++++---- src/idevicerestore.h | 3 +- src/ipsw.c | 430 +++++++++++++++++++++++++++++++++++++-------------- src/ipsw.h | 13 +- src/restore.c | 6 +- 8 files changed, 392 insertions(+), 166 deletions(-) diff --git a/configure.ac b/configure.ac index 4c066ea..c9fcb91 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,8 @@ case ${host_os} in AC_LDFLAGS+="-static-libgcc" ;; darwin*) - AC_MSG_RESULT([no]) + AC_MSG_RESULT([yes]) + AC_DEFINE([_DARWIN_BETTER_REALPATH], [1], [Use better method for realpath]) AX_PTHREAD([], [AC_MSG_ERROR([pthread is required to build $PACKAGE])]) ;; *) @@ -65,7 +66,7 @@ case ${host_os} in esac AM_CONDITIONAL(WIN32, test x$win32 = xtrue) -AC_CHECK_FUNCS([strsep strcspn mkstemp]) +AC_CHECK_FUNCS([strsep strcspn mkstemp realpath]) if test x$ac_cv_func_strsep != xyes; then if test x$ac_cv_func_strcspn != xyes; then AC_MSG_ERROR([You need either strsep or strcspn to build $PACKAGE]) diff --git a/src/common.c b/src/common.c index 559f342..d4b7c8d 100644 --- a/src/common.c +++ b/src/common.c @@ -2,8 +2,8 @@ * common.c * Misc functions used in idevicerestore * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -35,7 +35,6 @@ #include #include #include -#include #ifdef WIN32 #include @@ -486,6 +485,24 @@ char* strsep(char** strp, const char* delim) } #endif +#ifndef HAVE_REALPATH +char* realpath(const char *filename, char *resolved_name) +{ +#ifdef WIN32 + if (access(filename, F_OK) != 0) { + return NULL; + } + if (GetFullPathName(filename, MAX_PATH, resolved_name, NULL) == 0) { + return NULL; + } + return resolved_name; +#else +#error please provide a realpath implementation for this platform + return NULL; +#endif +} +#endif + #ifdef WIN32 #define BS_CC '\b' #define my_getch getch diff --git a/src/common.h b/src/common.h index dd854cb..6c568f8 100644 --- a/src/common.h +++ b/src/common.h @@ -2,8 +2,8 @@ * common.h * Misc functions used in idevicerestore * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -144,6 +144,10 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d char* strsep(char** strp, const char* delim); #endif +#ifndef HAVE_REALPATH +char* realpath(const char *filename, char *resolved_name); +#endif + void get_user_input(char *buf, int maxlen, int secure); #ifdef __cplusplus diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 9337763..83aefa3 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2,8 +2,8 @@ * idevicerestore.c * Restore device firmware and filesystem * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010-2015 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012-2015 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -77,32 +77,38 @@ static struct option longopts[] = { void usage(int argc, char* argv[]) { char* name = strrchr(argv[0], '/'); - printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); - printf("Restore IPSW firmware FILE to an iOS device.\n\n"); - printf(" -i, --ecid ECID\ttarget specific device by its ECID\n"); - printf(" \te.g. 0xaabb123456 (hex) or 1234567890 (decimal)\n"); - printf(" -u, --udid UDID\ttarget specific device by its device UDID\n"); - printf(" \tNOTE: only works with devices in normal mode.\n"); - printf(" -d, --debug\t\tenable communication debugging\n"); - printf(" -h, --help\t\tprints usage information\n"); - printf(" -e, --erase\t\tperform a full restore, erasing all data (defaults to update)\n"); - printf(" -c, --custom\t\trestore with a custom firmware\n"); - printf(" -l, --latest\t\tuse latest available firmware (with download on demand)\n"); - printf(" \t\tDO NOT USE if you need to preserve the baseband (unlock)!\n"); - printf(" \t\tUSE WITH CARE if you want to keep a jailbreakable firmware!\n"); - printf(" \t\tThe FILE argument is ignored when using this option.\n"); - printf(" -s, --cydia\t\tuse Cydia's signature service instead of Apple's\n"); - printf(" -x, --exclude\t\texclude nor/baseband upgrade\n"); - printf(" -t, --shsh\t\tfetch TSS record and save to .shsh file, then exit\n"); - printf(" -k, --keep-pers\twrite personalized components to files for debugging\n"); - printf(" -p, --pwn\t\tput device in pwned DFU mode and exit (limera1n devices only)\n"); - printf(" -n, --no-action\tDo not perform any restore action. If combined with -l option\n"); - printf(" \tthe on demand ipsw download is performed before exiting.\n"); - printf(" -C, --cache-path DIR\tUse specified directory for caching extracted\n"); - printf(" \tor other reused files.\n"); - printf(" -y, --no-input\t\tNon-interactive mode, do not ask for any input\n"); - printf("\n"); - printf("Homepage: <" PACKAGE_URL ">\n"); + printf("Usage: %s [OPTIONS] PATH\n" \ + "Restore IPSW firmware at PATH to an iOS device.\n" \ + "\n" \ + "PATH can be a compressed .ipsw file or a directory containing all files\n" \ + "extracted from an IPSW.\n" \ + "\n" \ + "Options:\n" \ + " -i, --ecid ECID target specific device by its ECID\n" \ + " e.g. 0xaabb123456 (hex) or 1234567890 (decimal)\n" \ + " -u, --udid UDID target specific device by its device UDID\n" \ + " NOTE: only works with devices in normal mode.\n" \ + " -d, --debug enable communication debugging\n" \ + " -h, --help prints usage information\n" \ + " -e, --erase perform a full restore, erasing all data (defaults to update)\n" \ + " -c, --custom restore with a custom firmware\n" \ + " -l, --latest use latest available firmware (with download on demand)\n" \ + " DO NOT USE if you need to preserve the baseband (unlock)!\n" \ + " USE WITH CARE if you want to keep a jailbreakable firmware!\n" \ + " The FILE argument is ignored when using this option.\n" \ + " -s, --cydia use Cydia's signature service instead of Apple's\n" \ + " -x, --exclude exclude nor/baseband upgrade\n" \ + " -t, --shsh fetch TSS record and save to .shsh file, then exit\n" \ + " -k, --keep-pers write personalized components to files for debugging\n" \ + " -p, --pwn put device in pwned DFU mode and exit (limera1n devices only)\n" \ + " -n, --no-action Do not perform any restore action. If combined with -l option\n" \ + " the on demand ipsw download is performed before exiting.\n" \ + " -C, --cache-path DIR Use specified directory for caching extracted\n" \ + " or other reused files.\n" \ + " -y, --no-input Non-interactive mode, do not ask for any input\n" \ + "\n" \ + "Homepage: <" PACKAGE_URL ">", + (name ? name + 1 : argv[0])); } #endif @@ -681,9 +687,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } else { strcpy(tmpf, client->ipsw); } - char* p = strrchr((const char*)tmpf, '.'); - if (p) { - *p = '\0'; + + if (!ipsw_is_directory(client->ipsw)) { + // strip off file extension if given ipsw is not a directory + char* s = tmpf + strlen(tmpf) - 1; + char* p = s; + while (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') p--; + if (s - p < 6) { + if (*p == '.') { + *p = '\0'; + } + } } if (stat(tmpf, &st) < 0) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 824c70f..40ebf29 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -2,8 +2,8 @@ * idevicerestore.h * Restore device firmware and filesystem * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012-2015 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -90,6 +90,7 @@ plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, cons plist_t build_manifest_get_build_identity_for_model_with_restore_behavior(plist_t build_manifest, const char *hardware_model, const char *behavior); int build_manifest_get_build_count(plist_t build_manifest); void build_identity_print_information(plist_t build_identity); +int build_identity_check_components_in_ipsw(plist_t build_identity, const char* ipsw); int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem); diff --git a/src/ipsw.c b/src/ipsw.c index c487edd..8ca6a8f 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -2,8 +2,8 @@ * ipsw.c * Utilities for extracting and manipulating IPSWs * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -21,10 +21,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#ifdef HAVE_CONFIG_H +#include +#endif #include #include #include +#include +#include +#include +#include +#include #include #include "ipsw.h" @@ -38,12 +45,29 @@ typedef struct { struct zip* zip; + char *path; } ipsw_archive; ipsw_archive* ipsw_open(const char* ipsw); void ipsw_close(ipsw_archive* archive); -ipsw_archive* ipsw_open(const char* ipsw) { +static char* build_path(const char* path, const char* file) +{ + size_t plen = strlen(path); + size_t flen = strlen(file); + char *fullpath = malloc(plen + flen + 2); + if (!fullpath) { + return NULL; + } + strncpy(fullpath, path, plen); + fullpath[plen] = '/'; + strncpy(fullpath+plen+1, file, flen); + fullpath[plen+1+flen] = '\0'; + return fullpath; +} + +ipsw_archive* ipsw_open(const char* ipsw) +{ int err = 0; ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); if (archive == NULL) { @@ -51,37 +75,72 @@ ipsw_archive* ipsw_open(const char* ipsw) { return NULL; } - archive->zip = zip_open(ipsw, 0, &err); - if (archive->zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw, err); - free(archive); + struct stat fst; + if (stat(ipsw, &fst) != 0) { + error("ERROR: ipsw_open %s: %s\n", ipsw, strerror(errno)); return NULL; } - + archive->path = strdup(ipsw); + if (S_ISDIR(fst.st_mode)) { + archive->zip = NULL; + } else { + archive->zip = zip_open(ipsw, 0, &err); + if (archive->zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw, err); + free(archive); + return NULL; + } + } return archive; } -int ipsw_get_file_size(const char* ipsw, const char* infile, off_t* size) { +int ipsw_is_directory(const char* ipsw) +{ + struct stat fst; + memset(&fst, '\0', sizeof(fst)); + if (stat(ipsw, &fst) != 0) { + return 0; + } + return S_ISDIR(fst.st_mode); +} + +int ipsw_get_file_size(const char* ipsw, const char* infile, off_t* size) +{ ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL || archive->zip == NULL) { + if (archive == NULL) { error("ERROR: Invalid archive\n"); return -1; } - int zindex = zip_name_locate(archive->zip, infile, 0); - if (zindex < 0) { - error("ERROR: zip_name_locate: %s\n", infile); - return -1; - } + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + error("ERROR: zip_name_locate: %s\n", infile); + ipsw_close(archive); + return -1; + } - struct zip_stat zstat; - zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index: %s\n", infile); - return -1; - } + struct zip_stat zstat; + zip_stat_init(&zstat); + if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + error("ERROR: zip_stat_index: %s\n", infile); + ipsw_close(archive); + return -1; + } + + *size = zstat.size; + } else { + char *filepath = build_path(archive->path, infile); + struct stat fst; + if (stat(filepath, &fst) != 0) { + free(filepath); + ipsw_close(archive); + return -1; + } + free(filepath); - *size = zstat.size; + *size = fst.st_size; + } ipsw_close(archive); return 0; @@ -91,72 +150,143 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con { int ret = 0; ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL || archive->zip == NULL) { + if (archive == NULL) { error("ERROR: Invalid archive\n"); return -1; } - int zindex = zip_name_locate(archive->zip, infile, 0); - if (zindex < 0) { - error("ERROR: zip_name_locate: %s\n", infile); - return -1; - } + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + error("ERROR: zip_name_locate: %s\n", infile); + return -1; + } - struct zip_stat zstat; - zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index: %s\n", infile); - return -1; - } + struct zip_stat zstat; + zip_stat_init(&zstat); + if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + error("ERROR: zip_stat_index: %s\n", infile); + return -1; + } - char* buffer = (char*) malloc(BUFSIZE); - if (buffer == NULL) { - error("ERROR: Unable to allocate memory\n"); - return -1; - } + char* buffer = (char*) malloc(BUFSIZE); + if (buffer == NULL) { + error("ERROR: Unable to allocate memory\n"); + return -1; + } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); - if (zfile == NULL) { - error("ERROR: zip_fopen_index: %s\n", infile); - return -1; - } + struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + if (zfile == NULL) { + error("ERROR: zip_fopen_index: %s\n", infile); + return -1; + } - FILE* fd = fopen(outfile, "wb"); - if (fd == NULL) { - error("ERROR: Unable to open output file: %s\n", outfile); - zip_fclose(zfile); - return -1; - } + FILE* fd = fopen(outfile, "wb"); + if (fd == NULL) { + error("ERROR: Unable to open output file: %s\n", outfile); + zip_fclose(zfile); + return -1; + } - off_t i, bytes = 0; - int count, size = BUFSIZE; - double progress; - for(i = zstat.size; i > 0; i -= count) { - if (i < BUFSIZE) - size = i; - count = zip_fread(zfile, buffer, size); - if (count < 0) { - error("ERROR: zip_fread: %s\n", infile); - ret = -1; - break; + off_t i, bytes = 0; + int count, size = BUFSIZE; + double progress; + for(i = zstat.size; i > 0; i -= count) { + if (i < BUFSIZE) + size = i; + count = zip_fread(zfile, buffer, size); + if (count < 0) { + error("ERROR: zip_fread: %s\n", infile); + ret = -1; + break; + } + if (fwrite(buffer, 1, count, fd) != count) { + error("ERROR: frite: %s\n", outfile); + ret = -1; + break; + } + + bytes += size; + if (print_progress) { + progress = ((double)bytes / (double)zstat.size) * 100.0; + print_progress_bar(progress); + } } - if (fwrite(buffer, 1, count, fd) != count) { - error("ERROR: frite: %s\n", outfile); + free(buffer); + fclose(fd); + zip_fclose(zfile); + } else { + char *filepath = build_path(archive->path, infile); + char actual_filepath[PATH_MAX+1]; + char actual_outfile[PATH_MAX+1]; + if (!realpath(filepath, actual_filepath)) { + error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno)); ret = -1; - break; - } + goto leave; + } else { + if (realpath(outfile, actual_outfile) && (strcmp(actual_filepath, actual_outfile) == 0)) { + /* files are identical */ + ret = 0; + } else { + FILE *fi = fopen(actual_filepath, "rb"); + if (!fi) { + error("ERROR: fopen: %s: %s\n", actual_filepath, strerror(errno)); + ret = -1; + goto leave; + } + struct stat fst; + if (fstat(fileno(fi), &fst) != 0) { + fclose(fi); + error("ERROR: fstat: %s: %s\n", actual_filepath, strerror(errno)); + ret = -1; + goto leave; + } + FILE *fo = fopen(actual_outfile, "wb"); + if (!fo) { + fclose(fi); + error("ERROR: fopen: %s: %s\n", actual_outfile, strerror(errno)); + ret = -1; + goto leave; + } + char* buffer = (char*) malloc(BUFSIZE); + if (buffer == NULL) { + fclose(fi); + fclose(fo); + error("ERROR: Unable to allocate memory\n"); + ret = -1; + goto leave;; + } - bytes += size; - if (print_progress) { - progress = ((double)bytes / (double)zstat.size) * 100.0; - print_progress_bar(progress); + uint64_t bytes = 0; + double progress; + while (!feof(fi)) { + ssize_t r = fread(buffer, 1, BUFSIZE, fi); + if (r < 0) { + error("ERROR: fread failed: %s\n", strerror(errno)); + ret = -1; + break; + } + if (fwrite(buffer, 1, r, fo) != r) { + error("ERROR: fwrite failed\n"); + ret = -1; + break; + } + bytes += r; + if (print_progress) { + progress = ((double)bytes / (double)fst.st_size) * 100.0; + print_progress_bar(progress); + } + } + + free(buffer); + fclose(fi); + fclose(fo); + } } + leave: + free(filepath); } - - fclose(fd); - zip_fclose(zfile); ipsw_close(archive); - free(buffer); return ret; } @@ -168,65 +298,123 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi int ipsw_file_exists(const char* ipsw, const char* infile) { ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL || archive->zip == NULL) { - return -1; + if (archive == NULL) { + return 0; } - int zindex = zip_name_locate(archive->zip, infile, 0); - if (zindex < 0) { - ipsw_close(archive); - return -2; + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + ipsw_close(archive); + return 0; + } + } else { + char *filepath = build_path(archive->path, infile); + if (access(filepath, R_OK) != 0) { + free(filepath); + ipsw_close(archive); + return 0; + } + free(filepath); } ipsw_close(archive); - return 0; + return 1; } -int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) { +int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) +{ + size_t size = 0; + unsigned char* buffer = NULL; ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL || archive->zip == NULL) { + if (archive == NULL) { error("ERROR: Invalid archive\n"); return -1; } - int zindex = zip_name_locate(archive->zip, infile, 0); - if (zindex < 0) { - debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); - return -1; - } + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); + ipsw_close(archive); + return -1; + } - struct zip_stat zstat; - zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index: %s\n", infile); - return -1; - } + struct zip_stat zstat; + zip_stat_init(&zstat); + if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + error("ERROR: zip_stat_index: %s\n", infile); + ipsw_close(archive); + return -1; + } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); - if (zfile == NULL) { - error("ERROR: zip_fopen_index: %s\n", infile); - return -1; - } + struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + if (zfile == NULL) { + error("ERROR: zip_fopen_index: %s\n", infile); + ipsw_close(archive); + return -1; + } - int size = zstat.size; - unsigned char* buffer = (unsigned char*) malloc(size+1); - if (buffer == NULL) { - error("ERROR: Out of memory\n"); - zip_fclose(zfile); - return -1; - } + size = zstat.size; + buffer = (unsigned char*) malloc(size+1); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + zip_fclose(zfile); + ipsw_close(archive); + return -1; + } + + if (zip_fread(zfile, buffer, size) != size) { + error("ERROR: zip_fread: %s\n", infile); + zip_fclose(zfile); + free(buffer); + ipsw_close(archive); + return -1; + } + + buffer[size] = '\0'; - if (zip_fread(zfile, buffer, size) != size) { - error("ERROR: zip_fread: %s\n", infile); zip_fclose(zfile); - free(buffer); - return -1; - } + } else { + char *filepath = build_path(archive->path, infile); + FILE *f = fopen(filepath, "rb"); + if (!f) { + error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + ipsw_close(archive); + return -2; + } + struct stat fst; + if (fstat(fileno(f), &fst) != 0) { + fclose(f); + error("ERROR: %s: fstat failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + ipsw_close(archive); + return -1; + } - buffer[size] = '\0'; + size = fst.st_size; + buffer = (unsigned char*)malloc(size+1); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + fclose(f); + free(filepath); + ipsw_close(archive); + return -1; + } + if (fread(buffer, 1, size, f) != size) { + fclose(f); + error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + ipsw_close(archive); + return -1; + } + buffer[size] = '\0'; - zip_fclose(zfile); + fclose(f); + free(filepath); + } ipsw_close(archive); *pbuffer = buffer; @@ -234,14 +422,15 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** return 0; } -int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) { +int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) +{ unsigned int size = 0; unsigned char* data = NULL; *tss_enabled = 0; /* older devices don't require personalized firmwares and use a BuildManifesto.plist */ - if (ipsw_file_exists(ipsw, "BuildManifesto.plist") == 0) { + if (ipsw_file_exists(ipsw, "BuildManifesto.plist")) { if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) { plist_from_xml((char*)data, size, buildmanifest); free(data); @@ -263,7 +452,8 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t return -1; } -int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) { +int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) +{ unsigned int size = 0; unsigned char* data = NULL; @@ -276,10 +466,14 @@ int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) { return -1; } -void ipsw_close(ipsw_archive* archive) { +void ipsw_close(ipsw_archive* archive) +{ if (archive != NULL) { - zip_unchange_all(archive->zip); - zip_close(archive->zip); + free(archive->path); + if (archive->zip) { + zip_unchange_all(archive->zip); + zip_close(archive->zip); + } free(archive); } } diff --git a/src/ipsw.h b/src/ipsw.h index 1c19e92..4c0087f 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -2,7 +2,7 @@ * ipsw.h * Definitions for IPSW utilities * - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Martin Szulecki. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * @@ -28,24 +28,17 @@ extern "C" { #endif -#include #include #include -typedef struct { - int index; - char* name; - unsigned int size; - unsigned char* data; -} ipsw_file; - +int ipsw_is_directory(const char* ipsw); +int ipsw_file_exists(const char* ipsw, const char* infile); int ipsw_get_file_size(const char* ipsw, const char* infile, off_t* size); int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress); int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); -void ipsw_free_file(ipsw_file* file); int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares); int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char** ipswfile); diff --git a/src/restore.c b/src/restore.c index f222d8a..0f2ce89 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2,8 +2,8 @@ * restore.c * Functions for handling idevices in restore mode * + * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012-2015 Nikias Bassen. All Rights Reserved. * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * * This library is free software; you can redistribute it and/or @@ -938,7 +938,9 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); firmware_files = plist_new_dict(); - ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size); + if (ipsw_file_exists(client->ipsw, manifest_file)) { + ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size); + } if (manifest_data && manifest_size > 0) { info("Getting firmware manifest from %s\n", manifest_file); char *manifest_p = (char*)manifest_data; -- cgit v1.1-32-gdbae