diff options
Diffstat (limited to 'src/ipsw.c')
-rw-r--r-- | src/ipsw.c | 269 |
1 files changed, 154 insertions, 115 deletions
@@ -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; + } +} |