diff --git a/0001-add-hashAB-support-via-external-module.patch b/0001-add-hashAB-support-via-external-module.patch new file mode 100644 index 0000000..e31f432 --- /dev/null +++ b/0001-add-hashAB-support-via-external-module.patch @@ -0,0 +1,464 @@ +From 631669274078916a601ae1a4d56f41cb5236d842 Mon Sep 17 00:00:00 2001 +From: Nikias Bassen +Date: Mon, 4 Oct 2010 01:15:39 +0200 +Subject: [PATCH 1/3] add hashAB support via external module + +--- + configure.ac | 9 ++ + src/Makefile.am | 1 + + src/db-itunes-parser.h | 2 + + src/itdb_device.c | 1 + + src/itdb_hashAB.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/itdb_itunesdb.c | 30 ++++++-- + src/itdb_private.h | 8 ++ + src/itdb_sqlite.c | 54 ++++++++++---- + 8 files changed, 278 insertions(+), 23 deletions(-) + create mode 100644 src/itdb_hashAB.c + +diff --git a/configure.ac b/configure.ac +index 370a192..5858c57 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -217,6 +217,15 @@ AC_SUBST(TMPMOUNTDIR) + AH_TEMPLATE([TMPMOUNTDIR], [Directory where HAL/udev will create a sub-directory to mount iPods]) + AC_DEFINE_UNQUOTED(TMPMOUNTDIR, "$with_temp_mount_dir", [Directory where HAL/udev will create a sub-directory to mount iPods]) + ++dnl *********************************************************************** ++dnl * provide a $l{ibdir}/libgpod directory for external modules ++dnl * available via config.h as LIBGPOD_LIBDIR ++dnl *********************************************************************** ++ ++test "x${exec_prefix}" = "xNONE" && exec_prefix='${prefix}' ++LIBGPOD_LIBDIR=$(eval "echo \"$(eval "echo \"${libdir}\"")\"")/libgpod ++AC_DEFINE_UNQUOTED(LIBGPOD_LIBDIR,"$LIBGPOD_LIBDIR", [libgpod libdir]) ++ + dnl ************************************************** + dnl * TagLib is only used by test-rebuild-db + dnl ************************************************** +diff --git a/src/Makefile.am b/src/Makefile.am +index ce02831..1790d4f 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -11,6 +11,7 @@ libgpod_la_SOURCES = \ + itdb_device.c \ + itdb_hash58.c \ + itdb_hash72.c \ ++ itdb_hashAB.c \ + itdb_iphone.c \ + itdb_itunesdb.c \ + itdb_photoalbum.c \ +diff --git a/src/db-itunes-parser.h b/src/db-itunes-parser.h +index cc71bcc..80d5213 100644 +--- a/src/db-itunes-parser.h ++++ b/src/db-itunes-parser.h +@@ -102,6 +102,8 @@ struct _MhbdHeader { + guint16 unk_0xa4; + guint16 unk_0xa6; + guint16 unk_0xa8; ++ guchar align_0xa9; ++ guchar hashAB[57]; + guchar padding[]; + } __attribute__((__packed__)); + +diff --git a/src/itdb_device.c b/src/itdb_device.c +index fd256b4..bdc3dc3 100644 +--- a/src/itdb_device.c ++++ b/src/itdb_device.c +@@ -1920,6 +1920,7 @@ G_GNUC_INTERNAL gboolean itdb_device_write_checksum (Itdb_Device *device, + case ITDB_CHECKSUM_HASH72: + return itdb_hash72_write_hash (device, itdb_data, itdb_len, error); + case ITDB_CHECKSUM_HASHAB: ++ return itdb_hashAB_write_hash (device, itdb_data, itdb_len, error); + case ITDB_CHECKSUM_UNKNOWN: + g_set_error (error, 0, -1, "Unsupported checksum type"); + return FALSE; +diff --git a/src/itdb_hashAB.c b/src/itdb_hashAB.c +new file mode 100644 +index 0000000..6b64adb +--- /dev/null ++++ b/src/itdb_hashAB.c +@@ -0,0 +1,196 @@ ++/* ++| Copyright (c) 2010 Nikias Bassen ++| ++| The code contained in this file is free software; you can redistribute ++| it and/or modify it under the terms of the GNU Lesser General Public ++| License as published by the Free Software Foundation; either version ++| 2.1 of the License, or (at your option) any later version. ++| ++| This file is distributed in the hope that it will be useful, ++| but WITHOUT ANY WARRANTY; without even the implied warranty of ++| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++| Lesser General Public License for more details. ++| ++| You should have received a copy of the GNU Lesser General Public ++| License along with this code; if not, write to the Free Software ++| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++| USA ++| ++| iTunes and iPod are trademarks of Apple ++| ++| This product is not supported/written/published by Apple! ++*/ ++ ++#if HAVE_CONFIG_H ++#include ++#endif ++#include ++#include ++#include ++#include "rijndael.h" ++ ++#include ++ ++#include ++ ++#include "itdb_device.h" ++#include "db-itunes-parser.h" ++#include "itdb_private.h" ++ ++typedef void (*calcHashAB_t)(unsigned char target[57], const unsigned char sha1[20], const unsigned char uuid[20], const unsigned char rnd_bytes[23]); ++static calcHashAB_t calc_hashAB = NULL; ++ ++static gboolean load_libhashab() ++{ ++ gchar *path; ++ GModule *handle; ++ ++ if (!g_module_supported()) { ++ return FALSE; ++ } ++ path = g_module_build_path(LIBGPOD_LIBDIR, "hashab"); ++ handle = g_module_open(path, G_MODULE_BIND_LAZY); ++ if (!handle) { ++ g_free(path); ++ return FALSE; ++ } ++ g_free(path); ++ ++ if (!g_module_symbol(handle, "calcHashAB", (void**)&calc_hashAB)) { ++ g_module_close(handle); ++ g_warning("symbol 'calcHashAB' not found"); ++ return FALSE; ++ } ++ g_module_make_resident(handle); ++ ++ printf("***** hashAB support successfully loaded *****\n"); ++ ++ return TRUE; ++} ++ ++static void itdb_hashAB_compute_itunesdb_sha1 (unsigned char *itdb_data, ++ gsize itdb_len, ++ unsigned char sha1[20]) ++{ ++ guchar backup18[8]; ++ guchar backup32[20]; ++ guchar hashAB[57]; ++ gsize sha1_len; ++ GChecksum *checksum; ++ MhbdHeader *header; ++ ++ g_assert (itdb_len >= 0x6c); ++ ++ header = (MhbdHeader *)itdb_data; ++ g_assert (strncmp (header->header_id, "mhbd", strlen ("mhbd")) == 0); ++ memcpy (backup18, &header->db_id, sizeof (backup18)); ++ memcpy (backup32, &header->unk_0x32, sizeof (backup32)); ++ memcpy (hashAB, &header->hashAB, sizeof (hashAB)); ++ ++ /* Those fields must be zero'ed out for the sha1 calculation */ ++ memset(&header->db_id, 0, sizeof (header->db_id)); ++ ++ memset(&header->hash58, 0, sizeof (header->hash58)); ++ memset(&header->hash72, 0, sizeof (header->hash72)); ++ memset(&header->hashAB, 0, sizeof (header->hashAB)); ++ ++ sha1_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); ++ checksum = g_checksum_new (G_CHECKSUM_SHA1); ++ g_checksum_update (checksum, itdb_data, itdb_len); ++ g_checksum_get_digest (checksum, sha1, &sha1_len); ++ g_checksum_free (checksum); ++ ++ memcpy (&header->db_id, backup18, sizeof (backup18)); ++ memcpy (&header->unk_0x32, backup32, sizeof (backup32)); ++} ++ ++static int ord_from_hex_char(const char c) ++{ ++ if ('0' <= c && c <= '9') ++ return c - '0'; ++ else if ('a' <= c && c <= 'f') ++ return 10 + (c - 'a'); ++ else if ('A' <= c && c <= 'F') ++ return 10 + (c - 'A'); ++ else ++ return -1; ++} ++ ++static int string_to_hex(unsigned char *dest, const int array_size, ++ const char *s) ++{ ++ /* skip optional '0x' prefix */ ++ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ++ s += 2; ++ ++ if (strlen(s) > array_size*2) ++ return -8; ++ ++ do { ++ int low, high; ++ if((high = ord_from_hex_char(s[0])) == -1 || ++ (low = ord_from_hex_char(s[1])) == -1) ++ return -9; ++ *dest++ = high<<4 | low; ++ } while(*(s+=2)); ++ return 0; ++} ++ ++static gboolean get_uuid (const Itdb_Device *device, unsigned char uuid[20]) ++{ ++ const char *uuid_str; ++ int result; ++ ++ uuid_str = itdb_device_get_uuid (device); ++ if (uuid_str == NULL) { ++ uuid_str = itdb_device_get_firewire_id (device); ++ } ++ if (uuid_str == NULL) { ++ return FALSE; ++ } ++ memset (uuid, 0, 20); ++ result = string_to_hex (uuid, 20, uuid_str); ++ ++ return (result == 0); ++} ++ ++gboolean itdb_hashAB_compute_hash_for_sha1 (const Itdb_Device *device, ++ const guchar sha1[20], ++ guchar signature[57], ++ GError **error) ++{ ++ unsigned char uuid[20]; ++ unsigned char rndpart[23] = "ABCDEFGHIJKLMNOPQRSTUVW"; ++ ++ if (calc_hashAB == NULL) { ++ if (!load_libhashab()) { ++ g_set_error (error, 0, -1, "Unsupported checksum type"); ++ return FALSE; ++ } ++ } ++ ++ if (!get_uuid(device, uuid)) return FALSE; ++ ++ calc_hashAB(signature, sha1, uuid, rndpart); ++ ++ return TRUE; ++} ++ ++gboolean itdb_hashAB_write_hash (const Itdb_Device *device, ++ unsigned char *itdb_data, ++ gsize itdb_len, ++ GError **error) ++{ ++ guchar sha1[20]; ++ MhbdHeader *header; ++ ++ if (itdb_len < 0xF4) { ++ g_set_error (error, 0, -1, "iTunesDB file too small to write checksum"); ++ return FALSE; ++ } ++ ++ header = (MhbdHeader *)itdb_data; ++ header->hashing_scheme = GUINT16_FROM_LE (ITDB_CHECKSUM_HASHAB); ++ itdb_hashAB_compute_itunesdb_sha1 (itdb_data, itdb_len, sha1); ++ return itdb_hashAB_compute_hash_for_sha1 (device, sha1, header->hashAB, error); ++} +diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c +index 18fc780..bc55f4a 100644 +--- a/src/itdb_itunesdb.c ++++ b/src/itdb_itunesdb.c +@@ -3731,7 +3731,7 @@ static void mk_mhbd (FExport *fexp, guint32 children) + cts = fexp->wcontents; + + put_header (cts, "mhbd"); +- put32lint (cts, 188); /* header size */ ++ put32lint (cts, 244); /* header size */ + put32lint (cts, -1); /* size of whole mhdb -- fill in later */ + if (itdb_device_supports_compressed_itunesdb (fexp->itdb->device)) { + /* 2 on iPhone 3.0 and Nano 5G, 1 on iPod Color and iPod Classic +@@ -3760,10 +3760,12 @@ static void mk_mhbd (FExport *fexp, guint32 children) + 0x19 = iTunes 7.4 + 0x28 = iTunes 8.2.1 + 0x2a = iTunes 9.0.1 ++ 0x2e = iTunes 9.1 ++ 0x30 = iTunes 9.2 + Be aware that newer ipods won't work if the library version number is too + old + */ +- fexp->itdb->version = 0x2a; ++ fexp->itdb->version = 0x30; + put32lint (cts, fexp->itdb->version); + put32lint (cts, children); + put64lint (cts, fexp->itdb->id); +@@ -3787,20 +3789,32 @@ static void mk_mhbd (FExport *fexp, guint32 children) + /* seen: 0x01 for iPod Color */ + put32lint (cts, fexp->itdb->priv->unk_0x54); /* unknown: seen: 0x4d for nano 3G */ + /* seen: 0x0f for iPod Color */ +- put32_n0 (cts, 5); /* 20 bytes hash */ ++ put32_n0 (cts, 5); /* 20 bytes hash58 */ + put32lint (cts, fexp->itdb->tzoffset); /* timezone offset in seconds */ + /* 0x70 */ +- put16lint (cts, 2); /* without it, iTunes thinks iPhone databases +- are corrupted, 0 on iPod Color */ +- put16lint (cts, 0); +- put32_n0 (cts, 11); /* new hash */ ++ switch (itdb_device_get_checksum_type(fexp->itdb->device)) { ++ case ITDB_CHECKSUM_HASHAB: ++ put16lint (cts, 4); /* new on i4 */ ++ break; ++ case ITDB_CHECKSUM_HASH72: ++ put16lint (cts, 2); ++ break; ++ default: ++ put16lint (cts, 0); ++ break; ++ } ++ put16lint (cts, 0); /* hash72 */ ++ put32_n0 (cts, 11); /* hash72 */ + /* 0xa0 */ + put16lint (cts, fexp->itdb->priv->audio_language); /* audio_language */ + put16lint (cts, fexp->itdb->priv->subtitle_language); /* subtitle_language */ + put16lint (cts, fexp->itdb->priv->unk_0xa4); /* unknown */ + put16lint (cts, fexp->itdb->priv->unk_0xa6); /* unknown */ + put16lint (cts, fexp->itdb->priv->unk_0xa8); /* unknown */ +- put16lint (cts, 0); ++ put8int (cts, 0); ++ /* 0xab */ ++ put8int (cts, 0); /* hashAB */ ++ put32_n0 (cts, 14); /* hashAB */ + put32_n0 (cts, 4); /* dummy space */ + } + +diff --git a/src/itdb_private.h b/src/itdb_private.h +index 7f78967..4eec250 100644 +--- a/src/itdb_private.h ++++ b/src/itdb_private.h +@@ -229,6 +229,10 @@ G_GNUC_INTERNAL guint64 device_time_time_t_to_mac (Itdb_Device *device, + time_t timet); + G_GNUC_INTERNAL gint itdb_musicdirs_number_by_mountpoint (const gchar *mountpoint); + G_GNUC_INTERNAL int itdb_sqlite_generate_itdbs(FExport *fexp); ++G_GNUC_INTERNAL gboolean itdb_hashAB_write_hash (const Itdb_Device *device, ++ unsigned char *itdb_data, ++ gsize itdb_len, ++ GError **error); + G_GNUC_INTERNAL gboolean itdb_hash72_extract_hash_info(const Itdb_Device *device, + unsigned char *itdb_data, + gsize itdb_len); +@@ -240,6 +244,10 @@ G_GNUC_INTERNAL gboolean itdb_hash58_write_hash (Itdb_Device *device, + unsigned char *itdb_data, + gsize itdb_len, + GError **error); ++G_GNUC_INTERNAL gboolean itdb_hashAB_compute_hash_for_sha1 (const Itdb_Device *device, ++ const guchar sha1[20], ++ guchar signature[57], ++ GError **error); + G_GNUC_INTERNAL gboolean itdb_hash72_compute_hash_for_sha1 (const Itdb_Device *device, + const guchar sha1[20], + guchar signature[46], +diff --git a/src/itdb_sqlite.c b/src/itdb_sqlite.c +index b107e4e..974aa6c 100644 +--- a/src/itdb_sqlite.c ++++ b/src/itdb_sqlite.c +@@ -1860,24 +1860,22 @@ error: + return FALSE; + } + +-static const guint CBK_HEADER_SIZE = 46; +- +-static void cbk_calc_sha1_of_sha1s(GArray *cbk) ++static void cbk_calc_sha1_of_sha1s(GArray *cbk, guint cbk_header_size) + { + GChecksum *checksum; + unsigned char* final_sha1; + unsigned char* sha1s; + gsize final_sha1_len; + +- g_assert (cbk->len > CBK_HEADER_SIZE + 20); ++ g_assert (cbk->len > cbk_header_size + 20); + +- final_sha1 = &g_array_index(cbk, guchar, CBK_HEADER_SIZE); +- sha1s = &g_array_index(cbk, guchar, CBK_HEADER_SIZE + 20); ++ final_sha1 = &g_array_index(cbk, guchar, cbk_header_size); ++ sha1s = &g_array_index(cbk, guchar, cbk_header_size + 20); + final_sha1_len = g_checksum_type_get_length(G_CHECKSUM_SHA1); + g_assert (final_sha1_len == 20); + + checksum = g_checksum_new(G_CHECKSUM_SHA1); +- g_checksum_update(checksum, sha1s, cbk->len - (CBK_HEADER_SIZE + 20)); ++ g_checksum_update(checksum, sha1s, cbk->len - (cbk_header_size + 20)); + g_checksum_get_digest(checksum, final_sha1, &final_sha1_len); + g_checksum_free(checksum); + } +@@ -1888,12 +1886,30 @@ static gboolean mk_Locations_cbk(Itdb_iTunesDB *itdb, const char *dirname) + char *cbk_filename; + GArray *cbk; + gboolean success; +- guchar *cbk_hash72; ++ guchar *cbk_hash; + guchar *final_sha1; ++ guint cbk_header_size = 0; ++ guint checksum_type; ++ ++ checksum_type = itdb_device_get_checksum_type(itdb->device); ++ switch (checksum_type) { ++ case ITDB_CHECKSUM_HASHAB: ++ cbk_header_size = 57; ++ break; ++ case ITDB_CHECKSUM_HASH72: ++ cbk_header_size = 46; ++ break; ++ default: ++ break; ++ } ++ if (cbk_header_size == 0) { ++ fprintf(stderr, "ERROR: Unsupported checksum type '%d' in cbk file generation!\n", checksum_type); ++ return FALSE; ++ } + + cbk = g_array_sized_new(FALSE, TRUE, 1, +- CBK_HEADER_SIZE + 20); +- g_array_set_size(cbk, CBK_HEADER_SIZE + 20); ++ cbk_header_size + 20); ++ g_array_set_size(cbk, cbk_header_size + 20); + + locations_filename = g_build_filename(dirname, "Locations.itdb", NULL); + success = cbk_calc_sha1s(locations_filename, cbk); +@@ -1902,11 +1918,19 @@ static gboolean mk_Locations_cbk(Itdb_iTunesDB *itdb, const char *dirname) + g_array_free(cbk, TRUE); + return FALSE; + } +- cbk_calc_sha1_of_sha1s(cbk); +- final_sha1 = &g_array_index(cbk, guchar, CBK_HEADER_SIZE); +- cbk_hash72 = &g_array_index(cbk, guchar, 0); +- success = itdb_hash72_compute_hash_for_sha1 (itdb->device, final_sha1, +- cbk_hash72, NULL); ++ cbk_calc_sha1_of_sha1s(cbk, cbk_header_size); ++ final_sha1 = &g_array_index(cbk, guchar, cbk_header_size); ++ cbk_hash = &g_array_index(cbk, guchar, 0); ++ switch (checksum_type) { ++ case ITDB_CHECKSUM_HASHAB: ++ success = itdb_hashAB_compute_hash_for_sha1 (itdb->device, final_sha1, cbk_hash, NULL); ++ break; ++ case ITDB_CHECKSUM_HASH72: ++ success = itdb_hash72_compute_hash_for_sha1 (itdb->device, final_sha1, cbk_hash, NULL); ++ break; ++ default: ++ break; ++ } + if (!success) { + g_array_free(cbk, TRUE); + return FALSE; +-- +1.7.3.2 + diff --git a/0002-read-genius_cuid-mhsd-type-9-and-also-write-it-back.patch b/0002-read-genius_cuid-mhsd-type-9-and-also-write-it-back.patch new file mode 100644 index 0000000..f645a8e --- /dev/null +++ b/0002-read-genius_cuid-mhsd-type-9-and-also-write-it-back.patch @@ -0,0 +1,209 @@ +From 4e9548b131ed9fc8f535e6a6840544f69eb230c4 Mon Sep 17 00:00:00 2001 +From: Nikias Bassen +Date: Mon, 4 Oct 2010 01:56:52 +0200 +Subject: [PATCH 2/3] read genius_cuid (mhsd type 9) and also write it back + +This new mhsd of type 9 is new since iOS4. It just holds the genius cuid +if genius is activated. Otherwise, this mhsd node is not written to the +iTunesCDB file. Also updates the genius_cuid field in the db_info sqlite +table if available. +--- + src/itdb_itunesdb.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++- + src/itdb_private.h | 1 + + src/itdb_sqlite.c | 7 +++- + 3 files changed, 98 insertions(+), 4 deletions(-) + +diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c +index bc55f4a..4e2debb 100644 +--- a/src/itdb_itunesdb.c ++++ b/src/itdb_itunesdb.c +@@ -1335,6 +1335,7 @@ void itdb_free (Itdb_iTunesDB *itdb) + itdb_device_free (itdb->device); + if (itdb->userdata && itdb->userdata_destroy) + (*itdb->userdata_destroy) (itdb->userdata); ++ g_free (itdb->priv->genius_cuid); + g_free (itdb->priv); + g_free (itdb); + } +@@ -2988,6 +2989,47 @@ static gboolean parse_playlists (FImport *fimp, glong mhsd_seek) + return TRUE; + } + ++static gboolean parse_genius_mhsd(FImport *fimp, glong mhsd_seek) ++{ ++ FContents *cts; ++ guint32 hdrlen, mhsdlen; ++ gint32 len; ++ gchar *genius_cuid; ++ ++ g_return_val_if_fail (fimp, FALSE); ++ g_return_val_if_fail (fimp->itdb, FALSE); ++ g_return_val_if_fail (fimp->fcontents, FALSE); ++ g_return_val_if_fail (fimp->fcontents->filename, FALSE); ++ g_return_val_if_fail (mhsd_seek >= 0, FALSE); ++ ++ cts = fimp->fcontents; ++ ++ g_return_val_if_fail (check_header_seek (cts, "mhsd", mhsd_seek), ++ FALSE); ++ ++ hdrlen = get32lint (cts, mhsd_seek+4); ++ mhsdlen = get32lint (cts, mhsd_seek+8); ++ ++ len = mhsdlen - hdrlen; ++ if (len < 0) { ++ return FALSE; ++ } ++ ++ if (len != 32) { ++ g_warning(_("%s: Unexpected length %d for genius_cuid!\n"), __func__, len); ++ } ++ ++ genius_cuid = g_new0(gchar, len+1); ++ if (!seek_get_n_bytes (cts, genius_cuid, mhsd_seek+hdrlen, len)) { ++ g_free (genius_cuid); ++ return FALSE; ++ } ++ ++ fimp->itdb->priv->genius_cuid = genius_cuid; ++ ++ return TRUE; ++} ++ + static gboolean looks_like_itunesdb (FImport *fimp) + { + FContents *cts; +@@ -3019,7 +3061,7 @@ static gboolean parse_fimp (FImport *fimp, gboolean compressed) + { + glong seek=0; + FContents *cts; +- glong mhsd_1, mhsd_2, mhsd_3, mhsd_5; ++ glong mhsd_1, mhsd_2, mhsd_3, mhsd_5, mhsd_9; + + g_return_val_if_fail (fimp, FALSE); + g_return_val_if_fail (fimp->itdb, FALSE); +@@ -3053,6 +3095,10 @@ static gboolean parse_fimp (FImport *fimp, gboolean compressed) + mhsd_5 = find_mhsd (cts, 5); + CHECK_ERROR (fimp, FALSE); + ++ /* read genius cuid mhsd */ ++ mhsd_9 = find_mhsd (cts, 9); ++ CHECK_ERROR (fimp, FALSE); ++ + fimp->itdb->version = get32lint (cts, seek+0x10); + CHECK_ERROR (fimp, FALSE); + fimp->itdb->id = get64lint (cts, seek+0x18); +@@ -3130,6 +3176,10 @@ static gboolean parse_fimp (FImport *fimp, gboolean compressed) + parse_playlists (fimp, mhsd_5); + } + ++ if (mhsd_9 != -1) { ++ parse_genius_mhsd (fimp, mhsd_9); ++ } ++ + return TRUE; + } + +@@ -5585,6 +5635,26 @@ static gboolean write_mhsd_type6 (FExport *fexp) + return TRUE; + } + ++static gboolean write_genius_mhsd (FExport *fexp) ++{ ++ gulong mhsd_seek; ++ WContents *cts; ++ ++ g_return_val_if_fail (fexp, FALSE); ++ g_return_val_if_fail (fexp->itdb, FALSE); ++ g_return_val_if_fail (fexp->wcontents, FALSE); ++ ++ if (!fexp->itdb->priv->genius_cuid) { ++ return TRUE; ++ } ++ cts = fexp->wcontents; ++ mhsd_seek = cts->pos; /* get position of mhsd header */ ++ mk_mhsd (fexp, 9); /* write header */ ++ put_string (cts, fexp->itdb->priv->genius_cuid); ++ fix_header (cts, mhsd_seek); ++ return TRUE; ++} ++ + /* create a WContents structure */ + static WContents *wcontents_new (const gchar *filename) + { +@@ -5836,6 +5906,7 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB *itdb, + gulong mhbd_seek = 0; + WContents *cts; + gboolean result = TRUE; ++ guint32 num_mhsds; + + g_return_val_if_fail (itdb, FALSE); + g_return_val_if_fail (itdb->device, FALSE); +@@ -5870,7 +5941,15 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB *itdb, + } + #endif + +- mk_mhbd (fexp, 7); /* seven mhsds */ ++ /* default mhsd count */ ++ num_mhsds = 7; /* seven mhsds */ ++ ++ /* if genius_cuid present, we have one more */ ++ if (fexp->itdb->priv->genius_cuid) { ++ num_mhsds++; ++ } ++ ++ mk_mhbd (fexp, num_mhsds); + + /* write tracklist (mhsd type 1) */ + if (!fexp->error && !write_mhsd_tracks (fexp)) { +@@ -5933,6 +6012,17 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB *itdb, + goto err; + } + ++ if (fexp->itdb->priv->genius_cuid) { ++ /* write genius cuid (mhsd type 9) */ ++ if (!fexp->error && !write_genius_mhsd (fexp)) { ++ g_set_error (&fexp->error, ++ ITDB_FILE_ERROR, ++ ITDB_FILE_ERROR_ITDB_CORRUPT, ++ _("Error writing mhsd type 9")); ++ goto err; ++ } ++ } ++ + fix_header (cts, mhbd_seek); + + if (itdb_device_supports_compressed_itunesdb (itdb->device)) { +diff --git a/src/itdb_private.h b/src/itdb_private.h +index 4eec250..842250d 100644 +--- a/src/itdb_private.h ++++ b/src/itdb_private.h +@@ -198,6 +198,7 @@ struct _Itdb_iTunesDB_Private + gint16 unk_0xa4; + gint16 unk_0xa6; + gint16 unk_0xa8; ++ gchar *genius_cuid; + }; + + /* private data for Itdb_Track */ +diff --git a/src/itdb_sqlite.c b/src/itdb_sqlite.c +index 974aa6c..0f7272b 100644 +--- a/src/itdb_sqlite.c ++++ b/src/itdb_sqlite.c +@@ -894,8 +894,11 @@ static int mk_Library(Itdb_iTunesDB *itdb, + /* this is +0xA2 */ + sqlite3_bind_int(stmt_db_info, ++idx, itdb->priv->subtitle_language); + /* genius cuid */ +- /* TODO: unkown meaning, set to NULL */ +- sqlite3_bind_null(stmt_db_info, ++idx); ++ if (itdb->priv->genius_cuid) { ++ sqlite3_bind_text(stmt_db_info, ++idx, itdb->priv->genius_cuid, -1, SQLITE_STATIC); ++ } else { ++ sqlite3_bind_null(stmt_db_info, ++idx); ++ } + /* bib */ + /* TODO: unkown meaning, set to NULL */ + sqlite3_bind_null(stmt_db_info, ++idx); +-- +1.7.3.2 + diff --git a/0003-write-empty-mhsd-of-type-10.patch b/0003-write-empty-mhsd-of-type-10.patch new file mode 100644 index 0000000..c951cf8 --- /dev/null +++ b/0003-write-empty-mhsd-of-type-10.patch @@ -0,0 +1,67 @@ +From 157bddcb019f4cacc1808c4664d4f113d4b08f16 Mon Sep 17 00:00:00 2001 +From: Nikias Bassen +Date: Mon, 4 Oct 2010 02:00:47 +0200 +Subject: [PATCH 3/3] write empty mhsd of type 10 + +Found since iOS4. We don't know yet what this is for -- this is for +completeness. +--- + src/itdb_itunesdb.c | 28 +++++++++++++++++++++++++++- + 1 files changed, 27 insertions(+), 1 deletions(-) + +diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c +index 4e2debb..e08988f 100644 +--- a/src/itdb_itunesdb.c ++++ b/src/itdb_itunesdb.c +@@ -5655,6 +5655,23 @@ static gboolean write_genius_mhsd (FExport *fexp) + return TRUE; + } + ++static gboolean write_mhsd_type10 (FExport *fexp) ++{ ++ gulong mhsd_seek; ++ WContents *cts; ++ ++ g_return_val_if_fail (fexp, FALSE); ++ g_return_val_if_fail (fexp->itdb, FALSE); ++ g_return_val_if_fail (fexp->wcontents, FALSE); ++ ++ cts = fexp->wcontents; ++ mhsd_seek = cts->pos; /* get position of mhsd header */ ++ mk_mhsd (fexp, 10); /* write header */ ++ mk_mhlt (fexp, 0); /* for now, produce an empty set */ ++ fix_header (cts, mhsd_seek); ++ return TRUE; ++} ++ + /* create a WContents structure */ + static WContents *wcontents_new (const gchar *filename) + { +@@ -5942,7 +5959,7 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB *itdb, + #endif + + /* default mhsd count */ +- num_mhsds = 7; /* seven mhsds */ ++ num_mhsds = 8; /* eight mhsds */ + + /* if genius_cuid present, we have one more */ + if (fexp->itdb->priv->genius_cuid) { +@@ -6003,6 +6020,15 @@ static gboolean itdb_write_file_internal (Itdb_iTunesDB *itdb, + goto err; + } + ++ /* write empty mhsd type 10, whatever it is */ ++ if (!fexp->error && !write_mhsd_type10 (fexp)) { ++ g_set_error (&fexp->error, ++ ITDB_FILE_ERROR, ++ ITDB_FILE_ERROR_ITDB_CORRUPT, ++ _("Error writing mhsd type 10")); ++ goto err; ++ } ++ + /* write mhsd5 playlists */ + if (!fexp->error && !write_mhsd_playlists (fexp, 5)) { + g_set_error (&fexp->error, +-- +1.7.3.2 + diff --git a/libgpod.spec b/libgpod.spec index ae3c568..b6f7b9b 100644 --- a/libgpod.spec +++ b/libgpod.spec @@ -9,13 +9,19 @@ Summary: Library to access the contents of an iPod Name: libgpod Version: 0.8.0 -Release: 9%{?dist} +Release: 10%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.gtkpod.org/libgpod.html Source0: http://downloads.sourceforge.net/gtkpod/%{name}-%{version}.tar.gz # http://sourceforge.net/tracker/index.php?func=detail&aid=3059994&group_id=67873&atid=519273 Patch0: libgpod-0.8.0-x86-32.patch +# From http://gtkpod.git.sourceforge.net/git/gitweb.cgi?p=gtkpod/libgpod;a=summary +Patch1: 0001-add-hashAB-support-via-external-module.patch +Patch2: 0002-read-genius_cuid-mhsd-type-9-and-also-write-it-back.patch +Patch3: 0003-write-empty-mhsd-of-type-10.patch +BuildRequires: automake libtool + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: docbook-style-xsl BuildRequires: glib2-devel @@ -119,6 +125,10 @@ libgpod-sharp. %prep %setup -q %patch0 -p1 -b .x86-32 +%patch1 -p1 -b .hashAB +%patch2 -p1 -b .genius +%patch3 -p1 -b .mhsd +autoreconf -f # remove execute perms on the python examples as they'll be installed in %%doc chmod -x bindings/python/examples/*.py @@ -135,6 +145,8 @@ rm -rf %{buildroot} make DESTDIR=%{buildroot} install %find_lang %{name} +mkdir -p %{buildroot}/%{_libdir}/libgpod + # remove Makefiles from the python examples dir rm -rf bindings/python/examples/Makefile* @@ -174,7 +186,7 @@ rm -rf %{buildroot} /lib/udev/iphone-set-info /lib/udev/ipod-set-info /lib/udev/rules.d/*.rules - +%{_libdir}/libgpod/ %files devel %defattr(-, root, root, 0755) @@ -209,6 +221,9 @@ rm -rf %{buildroot} %endif %changelog +* Thu Jul 14 2011 Bastien Nocera 0.8.0-10 +- Add hashDB support + * Wed May 25 2011 Todd Zullinger - 0.8.0-9 - Fix tmpfiles.d user/group for /var/run/libgpod (#707787)