summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2019-02-14 00:26:25 +0100
committerGravatar Nikias Bassen2019-02-14 00:26:25 +0100
commit64e88489ee47f4e5dca458970688485a0a165c30 (patch)
tree6b54866538be3b62dd4e6b4896920c354787ce42
parentfbaafdaf87cc01197ad86812a46cf17b7b392b8e (diff)
downloadidevicerestore-64e88489ee47f4e5dca458970688485a0a165c30.tar.gz
idevicerestore-64e88489ee47f4e5dca458970688485a0a165c30.tar.bz2
Allow .ipsw files or extracted IPSW as source
-rw-r--r--configure.ac5
-rw-r--r--src/common.c21
-rw-r--r--src/common.h6
-rw-r--r--src/idevicerestore.c74
-rw-r--r--src/idevicerestore.h3
-rw-r--r--src/ipsw.c430
-rw-r--r--src/ipsw.h13
-rw-r--r--src/restore.c6
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 <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
-#include <unistd.h>
#ifdef WIN32
#include <windows.h>
@@ -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 <zip.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <zip.h>
#include <openssl/sha.h>
#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 <zip.h>
#include <stdint.h>
#include <plist/plist.h>
-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;