From 05d2bc0ba3d736e2034bd89c810457d6a80ad052 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 22 Aug 2012 22:03:44 +0200 Subject: Add support for CarrierBundle installation (.ipcc files) --- src/ideviceinstaller.c | 333 +++++++++++++++++++++++++++++++------------------ 1 file changed, 212 insertions(+), 121 deletions(-) diff --git a/src/ideviceinstaller.c b/src/ideviceinstaller.c index 67e06f9..acf2b6b 100644 --- a/src/ideviceinstaller.c +++ b/src/ideviceinstaller.c @@ -212,6 +212,7 @@ static void print_usage(int argc, char **argv) " -o list_all\t- list all types of apps\n" " -o xml\t\t- print full output as xml plist\n" " -i, --install ARCHIVE\tInstall app from package file specified by ARCHIVE.\n" + " \tARCHIVE can also be a .ipcc file for carrier bundles.\n" " -u, --uninstall APPID\tUninstall app specified by APPID.\n" " -g, --upgrade APPID\tUpgrade app specified by APPID.\n" " -L, --list-archives\tList archived applications, possible options:\n" @@ -525,152 +526,242 @@ run_again: goto leave_cleanup; } - /* extract iTunesMetadata.plist from package */ - char *zbuf = NULL; - uint32_t len = 0; - if (zip_f_get_contents(zf, "iTunesMetadata.plist", 0, &zbuf, &len) == 0) { - meta = plist_new_data(zbuf, len); - } - if (zbuf) { - free(zbuf); - } + plist_t client_opts = instproxy_client_options_new(); - /* we need to get the CFBundleName first */ - plist_t info = NULL; - zbuf = NULL; - len = 0; - if (zip_f_get_contents(zf, "Info.plist", ZIP_FL_NODIR, &zbuf, &len) < 0) { - zip_unchange_all(zf); - zip_close(zf); - goto leave_cleanup; - } - if (memcmp(zbuf, "bplist00", 8) == 0) { - plist_from_bin(zbuf, len, &info); - } else { - plist_from_xml(zbuf, len, &info); - } - free(zbuf); + if ((strlen(appid) > 5) && (strcmp(&appid[strlen(appid)-5], ".ipcc") == 0)) { + char* ipcc = strdup(appid); + if ((asprintf(&pkgname, "%s/%s", PKG_PATH, basename(ipcc)) > 0) && pkgname) { + afc_make_directory(afc, pkgname); + } - if (!info) { - fprintf(stderr, "Could not parse Info.plist!\n"); - zip_unchange_all(zf); - zip_close(zf); - goto leave_cleanup; - } + printf("Uploading %s package contents...\n", basename(ipcc)); + + /* extract the contents of the .ipcc file to PublicStaging/.ipcc directory */ + zip_uint64_t numzf = zip_get_num_entries(zf, 0); + zip_uint64_t i = 0; + for (i = 0; numzf > 0 && i < numzf; i++) { + const char* zname = zip_get_name(zf, i, 0); + char* dstpath = NULL; + if (!zname) continue; + if (zname[strlen(zname)-1] == '/') { + // directory + if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) > 0) && dstpath) { + afc_make_directory(afc, dstpath); } + free(dstpath); + dstpath = NULL; + } else { + // file + struct zip_file* zfile = zip_fopen_index(zf, i, 0); + if (!zfile) continue; + + if ((asprintf(&dstpath, "%s/%s/%s", PKG_PATH, basename(ipcc), zname) <= 0) || !dstpath || (afc_file_open(afc, dstpath, AFC_FOPEN_WRONLY, &af) != AFC_E_SUCCESS)) { + fprintf(stderr, "ERROR: can't open afc://%s for writing\n", dstpath); + free(dstpath); + dstpath = NULL; + zip_fclose(zfile); + continue; + } - char *bundlename = NULL; + struct zip_stat zs; + zip_stat_init(&zs); + if (zip_stat_index(zf, i, 0, &zs) != 0) { + fprintf(stderr, "ERROR: zip_stat_index %ld failed!\n", i); + free(dstpath); + dstpath = NULL; + zip_fclose(zfile); + continue; + } - plist_t bname = plist_dict_get_item(info, "CFBundleName"); - if (bname) { - plist_get_string_val(bname, &bundlename); - } - plist_free(info); + free(dstpath); + dstpath = NULL; + + zip_uint64_t zfsize = 0; + while (zfsize < zs.size) { + zip_int64_t amount = zip_fread(zfile, buf, sizeof(buf)); + if (amount == 0) { + break; + } + + if (amount > 0) { + uint32_t written, total = 0; + while (total < amount) { + written = 0; + if (afc_file_write(afc, af, buf, amount, &written) != + AFC_E_SUCCESS) { + fprintf(stderr, "AFC Write error!\n"); + break; + } + total += written; + } + if (total != amount) { + fprintf(stderr, "Error: wrote only %d of %zu\n", total, amount); + afc_file_close(afc, af); + zip_fclose(zfile); + free(dstpath); + goto leave_cleanup; + } + } + + zfsize += amount; + } - if (!bundlename) { - fprintf(stderr, "Could not determine CFBundleName!\n"); - zip_unchange_all(zf); - zip_close(zf); - goto leave_cleanup; - } + afc_file_close(afc, af); + af = 0; - char *sinfname = NULL; - if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundlename, bundlename) < 0) { - fprintf(stderr, "Out of memory!?\n"); - goto leave_cleanup; - } - free(bundlename); + zip_fclose(zfile); + } + } + free(ipcc); + printf("done.\n"); - /* extract .sinf from package */ - zbuf = NULL; - len = 0; - if (zip_f_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) { - sinf = plist_new_data(zbuf, len); - } - free(sinfname); - if (zbuf) { + instproxy_client_options_add(client_opts, "PackageType", "CarrierBundle", NULL); + } else { + /* extract iTunesMetadata.plist from package */ + char *zbuf = NULL; + uint32_t len = 0; + if (zip_f_get_contents(zf, "iTunesMetadata.plist", 0, &zbuf, &len) == 0) { + meta = plist_new_data(zbuf, len); + } + if (zbuf) { + free(zbuf); + } + + /* we need to get the CFBundleName first */ + plist_t info = NULL; + zbuf = NULL; + len = 0; + if (zip_f_get_contents(zf, "Info.plist", ZIP_FL_NODIR, &zbuf, &len) < 0) { + zip_unchange_all(zf); + zip_close(zf); + goto leave_cleanup; + } + if (memcmp(zbuf, "bplist00", 8) == 0) { + plist_from_bin(zbuf, len, &info); + } else { + plist_from_xml(zbuf, len, &info); + } free(zbuf); - } - zip_unchange_all(zf); - zip_close(zf); + if (!info) { + fprintf(stderr, "Could not parse Info.plist!\n"); + zip_unchange_all(zf); + zip_close(zf); + goto leave_cleanup; + } - /* copy archive to device */ - f = fopen(appid, "r"); - if (!f) { - fprintf(stderr, "fopen: %s: %s\n", appid, strerror(errno)); - goto leave_cleanup; - } + char *bundlename = NULL; - pkgname = NULL; - if (asprintf(&pkgname, "%s/%s", PKG_PATH, basename(appid)) < 0) { - fprintf(stderr, "Out of memory!?\n"); - goto leave_cleanup; - } + plist_t bname = plist_dict_get_item(info, "CFBundleName"); + if (bname) { + plist_get_string_val(bname, &bundlename); + } + plist_free(info); - printf("Copying '%s' --> '%s'\n", appid, pkgname); + if (!bundlename) { + fprintf(stderr, "Could not determine CFBundleName!\n"); + zip_unchange_all(zf); + zip_close(zf); + goto leave_cleanup; + } - char **strs = NULL; - if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { - if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { - fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); + char *sinfname = NULL; + if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundlename, bundlename) < 0) { + fprintf(stderr, "Out of memory!?\n"); + goto leave_cleanup; } - } - if (strs) { - int i = 0; - while (strs[i]) { - free(strs[i]); - i++; + free(bundlename); + + /* extract .sinf from package */ + zbuf = NULL; + len = 0; + if (zip_f_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) { + sinf = plist_new_data(zbuf, len); + } + free(sinfname); + if (zbuf) { + free(zbuf); } - free(strs); - } - if ((afc_file_open(afc, pkgname, AFC_FOPEN_WRONLY, &af) != - AFC_E_SUCCESS) || !af) { - fclose(f); - fprintf(stderr, "afc_file_open on '%s' failed!\n", pkgname); - free(pkgname); - goto leave_cleanup; - } + /* copy archive to device */ + f = fopen(appid, "r"); + if (!f) { + fprintf(stderr, "fopen: %s: %s\n", appid, strerror(errno)); + goto leave_cleanup; + } - size_t amount = 0; - do { - amount = fread(buf, 1, sizeof(buf), f); - if (amount > 0) { - uint32_t written, total = 0; - while (total < amount) { - written = 0; - if (afc_file_write(afc, af, buf, amount, &written) != - AFC_E_SUCCESS) { - fprintf(stderr, "AFC Write error!\n"); - break; - } - total += written; + pkgname = NULL; + if (asprintf(&pkgname, "%s/%s", PKG_PATH, basename(appid)) < 0) { + fprintf(stderr, "Out of memory!?\n"); + goto leave_cleanup; + } + + printf("Copying '%s' --> '%s'\n", appid, pkgname); + + char **strs = NULL; + if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) { + if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) { + fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH); + } + } + if (strs) { + int i = 0; + while (strs[i]) { + free(strs[i]); + i++; } - if (total != amount) { - fprintf(stderr, "Error: wrote only %d of %zu\n", total, + free(strs); + } + + if ((afc_file_open(afc, pkgname, AFC_FOPEN_WRONLY, &af) != + AFC_E_SUCCESS) || !af) { + fclose(f); + fprintf(stderr, "afc_file_open on '%s' failed!\n", pkgname); + free(pkgname); + goto leave_cleanup; + } + + size_t amount = 0; + do { + amount = fread(buf, 1, sizeof(buf), f); + if (amount > 0) { + uint32_t written, total = 0; + while (total < amount) { + written = 0; + if (afc_file_write(afc, af, buf, amount, &written) != + AFC_E_SUCCESS) { + fprintf(stderr, "AFC Write error!\n"); + break; + } + total += written; + } + if (total != amount) { + fprintf(stderr, "Error: wrote only %d of %zu\n", total, amount); - afc_file_close(afc, af); - fclose(f); - free(pkgname); - goto leave_cleanup; + afc_file_close(afc, af); + fclose(f); + free(pkgname); + goto leave_cleanup; + } } } - } - while (amount > 0); + while (amount > 0); - afc_file_close(afc, af); - fclose(f); + afc_file_close(afc, af); + fclose(f); - printf("done.\n"); + printf("done.\n"); - /* perform installation or upgrade */ - plist_t client_opts = instproxy_client_options_new(); - if (sinf) { - instproxy_client_options_add(client_opts, "ApplicationSINF", sinf, NULL); - } - if (meta) { - instproxy_client_options_add(client_opts, "iTunesMetadata", meta, NULL); + if (sinf) { + instproxy_client_options_add(client_opts, "ApplicationSINF", sinf, NULL); + } + if (meta) { + instproxy_client_options_add(client_opts, "iTunesMetadata", meta, NULL); + } } + zip_unchange_all(zf); + zip_close(zf); + + /* perform installation or upgrade */ if (install_mode) { printf("Installing '%s'\n", pkgname); #ifdef HAVE_LIBIMOBILEDEVICE_1_1 -- cgit v1.1-32-gdbae