summaryrefslogtreecommitdiffstats
path: root/src/ipsw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipsw.c')
-rw-r--r--src/ipsw.c269
1 files changed, 154 insertions, 115 deletions
diff --git a/src/ipsw.c b/src/ipsw.c
index fafe583..58d817c 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -55,16 +55,8 @@
#define BUFSIZE 0x100000
-typedef struct {
- struct zip* zip;
- char *path;
-} ipsw_archive;
-
static int cancel_flag = 0;
-ipsw_archive* ipsw_open(const char* ipsw);
-void ipsw_close(ipsw_archive* archive);
-
static char* build_path(const char* path, const char* file)
{
size_t plen = strlen(path);
@@ -118,11 +110,14 @@ int ipsw_print_info(const char* path)
uint32_t plist_len = 0;
if (memcmp(&magic, "PK\x03\x04", 4) == 0) {
+ ipsw_archive_t ipsw = ipsw_open(thepath);
unsigned int rlen = 0;
- if (ipsw_extract_to_memory(thepath, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) {
+ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) {
+ ipsw_close(ipsw);
error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n");
return -1;
}
+ ipsw_close(ipsw);
plist_len = (uint32_t)rlen;
} else {
size_t rlen = 0;
@@ -310,10 +305,10 @@ int ipsw_print_info(const char* path)
return 0;
}
-ipsw_archive* ipsw_open(const char* ipsw)
+ipsw_archive_t ipsw_open(const char* ipsw)
{
int err = 0;
- ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive));
+ ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct ipsw_archive));
if (archive == NULL) {
error("ERROR: Out of memory\n");
return NULL;
@@ -324,7 +319,6 @@ ipsw_archive* ipsw_open(const char* ipsw)
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 {
@@ -335,7 +329,20 @@ ipsw_archive* ipsw_open(const char* ipsw)
return NULL;
}
}
- return archive;
+ archive->path = strdup(ipsw);
+ return (ipsw_archive_t)archive;
+}
+
+void ipsw_close(ipsw_archive_t ipsw)
+{
+ if (ipsw != NULL) {
+ free(ipsw->path);
+ if (ipsw->zip) {
+ zip_unchange_all(ipsw->zip);
+ zip_close(ipsw->zip);
+ }
+ free(ipsw);
+ }
}
int ipsw_is_directory(const char* ipsw)
@@ -348,37 +355,33 @@ int ipsw_is_directory(const char* ipsw)
return S_ISDIR(fst.st_mode);
}
-int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size)
+int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size)
{
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
+ if (ipsw == NULL) {
error("ERROR: Invalid archive\n");
return -1;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->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) {
+ if (zip_stat_index(ipsw->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);
+ char *filepath = build_path(ipsw->path, infile);
struct stat fst;
if (stat(filepath, &fst) != 0) {
free(filepath);
- ipsw_close(archive);
return -1;
}
free(filepath);
@@ -386,30 +389,22 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size)
*size = fst.st_size;
}
- ipsw_close(archive);
return 0;
}
-int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress)
+int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress)
{
int ret = 0;
- ipsw_archive* archive = NULL;
if (!ipsw || !infile || !outfile) {
error("ERROR: Invalid argument\n");
return -1;
}
- archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
- return -1;
- }
-
cancel_flag = 0;
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->zip, infile, 0);
if (zindex < 0) {
error("ERROR: zip_name_locate: %s\n", infile);
return -1;
@@ -417,7 +412,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
struct zip_stat zstat;
zip_stat_init(&zstat);
- if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) {
+ if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) {
error("ERROR: zip_stat_index: %s\n", infile);
return -1;
}
@@ -428,7 +423,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
return -1;
}
- struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0);
+ struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0);
if (zfile == NULL) {
error("ERROR: zip_fopen_index: %s\n", infile);
return -1;
@@ -472,7 +467,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
fclose(fd);
zip_fclose(zfile);
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
char actual_filepath[PATH_MAX+1];
char actual_outfile[PATH_MAX+1];
if (!filepath) {
@@ -553,76 +548,66 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
leave:
free(filepath);
}
- ipsw_close(archive);
if (cancel_flag) {
ret = -2;
}
return ret;
}
-int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile)
+int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile)
{
return ipsw_extract_to_file_with_progress(ipsw, infile, outfile, 0);
}
-int ipsw_file_exists(const char* ipsw, const char* infile)
+int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile)
{
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
+ if (!ipsw) {
return 0;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->zip, infile, 0);
if (zindex < 0) {
- ipsw_close(archive);
return 0;
}
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
if (access(filepath, R_OK) != 0) {
free(filepath);
- ipsw_close(archive);
return 0;
}
free(filepath);
}
- ipsw_close(archive);
-
return 1;
}
-int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize)
+int ipsw_extract_to_memory(ipsw_archive_t 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) {
+ if (ipsw == NULL) {
error("ERROR: Invalid archive\n");
return -1;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->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) {
+ if (zip_stat_index(ipsw->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);
+ struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0);
if (zfile == NULL) {
error("ERROR: zip_fopen_index: %s\n", infile);
- ipsw_close(archive);
return -1;
}
@@ -631,7 +616,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
if (buffer == NULL) {
error("ERROR: Out of memory\n");
zip_fclose(zfile);
- ipsw_close(archive);
return -1;
}
@@ -639,7 +623,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
error("ERROR: zip_fread: %s\n", infile);
zip_fclose(zfile);
free(buffer);
- ipsw_close(archive);
return -1;
}
@@ -647,7 +630,7 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
zip_fclose(zfile);
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
struct stat fst;
#ifdef WIN32
if (stat(filepath, &fst) != 0) {
@@ -656,7 +639,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
#endif
error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
- ipsw_close(archive);
return -1;
}
size = fst.st_size;
@@ -664,7 +646,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
if (buffer == NULL) {
error("ERROR: Out of memory\n");
free(filepath);
- ipsw_close(archive);
return -1;
}
@@ -674,7 +655,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -1;
}
} else {
@@ -684,7 +664,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -2;
}
if (fread(buffer, 1, size, f) != size) {
@@ -692,7 +671,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -1;
}
fclose(f);
@@ -703,45 +681,40 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char**
free(filepath);
}
- ipsw_close(archive);
*pbuffer = buffer;
*psize = size;
return 0;
}
-int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx)
+int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx)
{
unsigned char* buffer = NULL;
size_t done = 0;
size_t total_size = 0;
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
+ if (ipsw == NULL) {
error("ERROR: Invalid archive\n");
return -1;
}
- if (archive->zip) {
- int zindex = zip_name_locate(archive->zip, infile, 0);
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->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) {
+ if (zip_stat_index(ipsw->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);
+ struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0);
if (zfile == NULL) {
error("ERROR: zip_fopen_index: %s\n", infile);
- ipsw_close(archive);
return -1;
}
@@ -750,7 +723,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
if (buffer == NULL) {
error("ERROR: Out of memory\n");
zip_fclose(zfile);
- ipsw_close(archive);
return -1;
}
@@ -771,10 +743,9 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
}
done += zr;
}
- zip_fclose(zfile);
free(buffer);
} else {
- char *filepath = build_path(archive->path, infile);
+ char *filepath = build_path(ipsw->path, infile);
struct stat fst;
#ifdef WIN32
if (stat(filepath, &fst) != 0) {
@@ -783,7 +754,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
#endif
error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
- ipsw_close(archive);
return -1;
}
total_size = fst.st_size;
@@ -791,7 +761,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
if (buffer == NULL) {
error("ERROR: Out of memory\n");
free(filepath);
- ipsw_close(archive);
return -1;
}
@@ -802,7 +771,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -1;
}
send_callback(ctx, buffer, (size_t)rl);
@@ -813,7 +781,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno));
free(filepath);
free(buffer);
- ipsw_close(archive);
return -2;
}
@@ -838,7 +805,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
free(filepath);
free(buffer);
}
- ipsw_close(archive);
if (done < total_size) {
error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size);
@@ -851,7 +817,7 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_
return 0;
}
-int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled)
+int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled)
{
unsigned int size = 0;
unsigned char* data = NULL;
@@ -881,7 +847,7 @@ 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(ipsw_archive_t ipsw, plist_t* restore_plist)
{
unsigned int size = 0;
unsigned char* data = NULL;
@@ -895,10 +861,10 @@ int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist)
return -1;
}
-static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, ipsw_list_cb cb, void *ctx)
+static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ipsw_list_cb cb, void *ctx)
{
int ret = 0;
- char *base = build_path(archive->path, path);
+ char *base = build_path(ipsw->path, path);
DIR *dirp = opendir(base);
@@ -936,10 +902,10 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i
break;
}
- ret = cb(ctx, archive->path, subpath, &st);
+ ret = cb(ctx, ipsw, subpath, &st);
if (ret >= 0 && S_ISDIR(st.st_mode))
- ipsw_list_contents_recurse(archive, subpath, cb, ctx);
+ ipsw_list_contents_recurse(ipsw, subpath, cb, ctx);
free(fpath);
free(subpath);
@@ -950,21 +916,19 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i
return ret;
}
-int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
+int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx)
{
int ret = 0;
- ipsw_archive* archive = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+ if (ipsw == NULL) {
+ error("ERROR: Invalid IPSW archive\n");
return -1;
}
- if (archive->zip) {
- int64_t entries = zip_get_num_entries(archive->zip, 0);
+ if (ipsw->zip) {
+ int64_t entries = zip_get_num_entries(ipsw->zip, 0);
if (entries < 0) {
error("ERROR: zip_get_num_entries failed\n");
- ipsw_close(archive);
return -1;
}
@@ -972,7 +936,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
zip_stat_t stat;
zip_stat_init(&stat);
- if (zip_stat_index(archive->zip, index, 0, &stat) < 0) {
+ if (zip_stat_index(ipsw->zip, index, 0, &stat) < 0) {
error("ERROR: zip_stat_index failed for %s\n", stat.name);
ret = -1;
continue;
@@ -980,7 +944,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
uint8_t opsys;
uint32_t attributes;
- if (zip_file_get_external_attributes(archive->zip, index, 0, &opsys, &attributes) < 0) {
+ if (zip_file_get_external_attributes(ipsw->zip, index, 0, &opsys, &attributes) < 0) {
error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name);
ret = -1;
continue;
@@ -1010,25 +974,12 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx)
break;
}
} else {
- ret = ipsw_list_contents_recurse(archive, "", cb, ctx);
+ ret = ipsw_list_contents_recurse(ipsw, "", cb, ctx);
}
- ipsw_close(archive);
return ret;
}
-void ipsw_close(ipsw_archive* archive)
-{
- if (archive != NULL) {
- free(archive->path);
- if (archive->zip) {
- zip_unchange_all(archive->zip);
- zip_close(archive->zip);
- }
- free(archive);
- }
-}
-
int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares)
{
char url[256];
@@ -1352,3 +1303,91 @@ void ipsw_cancel(void)
{
cancel_flag++;
}
+
+ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path)
+{
+ ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle));
+ if (ipsw->zip) {
+ int zindex = zip_name_locate(ipsw->zip, path, 0);
+ if (zindex < 0) {
+ error("ERROR: zip_name_locate: %s not found\n", path);
+ free(handle);
+ return NULL;
+ }
+ handle->zfile = zip_fopen_index(ipsw->zip, zindex, 0);
+ if (handle->zfile == NULL) {
+ error("ERROR: zip_fopen_index: %s could not be opened\n", path);
+ free(handle);
+ return NULL;
+ }
+
+ } else {
+ char *filepath = build_path(ipsw->path, path);
+ handle->file = fopen(filepath, "rb");
+ free(filepath);
+ if (!handle->file) {
+ error("ERROR: fopen: %s could not be opened\n", path);
+ free(handle);
+ return NULL;
+ }
+ }
+ return handle;
+}
+
+void ipsw_file_close(ipsw_file_handle_t handle)
+{
+ if (handle && handle->zfile) {
+ zip_fclose(handle->zfile);
+ } else if (handle && handle->file) {
+ fclose(handle->file);
+ }
+ free(handle);
+}
+
+int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size)
+{
+ if (handle && handle->zfile) {
+ zip_int64_t zr = zip_fread(handle->zfile, buffer, size);
+ return (int64_t)zr;
+ } else if (handle && handle->file) {
+ return fread(buffer, 1, size, handle->file);
+ } else {
+ error("ERROR: %s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}
+
+int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence)
+{
+ if (handle && handle->zfile) {
+ return zip_fseek(handle->zfile, offset, whence);
+ } else if (handle && handle->file) {
+#ifdef WIN32
+ if (whence == SEEK_SET) {
+ rewind(handle->file);
+ }
+ return (_lseeki64(fileno(handle->file), offset, whence) < 0) ? -1 : 0;
+#else
+ return fseeko(handle->file, offset, whence);
+#endif
+ } else {
+ error("ERROR: %s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}
+
+int64_t ipsw_file_tell(ipsw_file_handle_t handle)
+{
+ if (handle && handle->zfile) {
+ return zip_ftell(handle->zfile);
+ } else if (handle && handle->file) {
+#ifdef WIN32
+ return _lseeki64(fileno(handle->file), 0, SEEK_CUR);
+#else
+ return ftello(handle->file);
+#endif
+ } else {
+ error("ERROR: %s: Invalid file handle\n", __func__);
+ return -1;
+ }
+}