From 91f1ea8c41a98989fcd2d9ed66640b9f682df5b5 Mon Sep 17 00:00:00 2001 From: Reupen Shah Date: Wed, 20 Jun 2018 20:16:50 +0100 Subject: [PATCH 1/3] Set version to 0.7.1 --- foo_dop/api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foo_dop/api.cpp b/foo_dop/api.cpp index a445b29..d179270 100644 --- a/foo_dop/api.cpp +++ b/foo_dop/api.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" // Fourth component of version no longer used -dop::ipod_manager_control_t::version_data_t g_version = {0, 7, 0, 0}; +dop::ipod_manager_control_t::version_data_t g_version = {0, 7, 1, 0}; /** Declare some information about our component */ DECLARE_COMPONENT_VERSION_COPY("iPod manager", From 52f4670079264e25cf4cb386d6ee012f288fea8a Mon Sep 17 00:00:00 2001 From: Reupen Shah Date: Wed, 20 Jun 2018 20:23:05 +0100 Subject: [PATCH 2/3] Retry iGSC checkpoint page retrieval when a corrupted page is detected --- foo_dop/device_info.cpp | 80 +++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/foo_dop/device_info.cpp b/foo_dop/device_info.cpp index 924803a..477fa07 100644 --- a/foo_dop/device_info.cpp +++ b/foo_dop/device_info.cpp @@ -48,6 +48,56 @@ struct io_ctrl_igsc { t_uint8 m_buffer[buffer]; }; +bool is_checkpoint_page_corrupted(gsl::span data) +{ + return std::find(data.begin(), data.end(), 0) != data.end(); +} + +std::tuple, bool> get_igsc_checkpoint_page(const win32::handle_ptr_t& volume, uint16_t page) +{ + constexpr auto chunk_size = 0x1000u; + constexpr auto header_size = 0x8u; + + io_ctrl_igsc data{}; + data.v0 = -64; + data.v1 = 64; + data.v2 = 2; + data.v3 = page; + data.v4 = chunk_size; + + constexpr auto max_attempts = 5; + constexpr auto initial_retry_delay_ms = 2u; + DWORD num_bytes_returned{}; + bool is_corrupt{}; + + for (auto attempt{0u}; attempt < max_attempts; ++attempt) { + const auto res = DeviceIoControl(volume, 0x2200A0, &data, sizeof(data), &data, sizeof(data), &num_bytes_returned, NULL); + + if (!res) + throw exception_win32(GetLastError()); + + if (num_bytes_returned < header_size) + throw exception_io_data_truncation(); + + const auto data_size = num_bytes_returned - header_size; + + is_corrupt = is_checkpoint_page_corrupted(gsl::span(data.m_buffer, data_size)); + + if (!is_corrupt) { + std::vector page_data(std::begin(data.m_buffer), std::begin(data.m_buffer) + data_size); + return {page_data, data_size == chunk_size}; + } + + console::formatter formatter; + formatter << "Detected a corrupt checkpoint data page; requerying page " << page << "..."; + + Sleep(initial_retry_delay_ms << attempt); + } + + pfc::string_formatter formatter; + throw exception_io_data(formatter << "Checkpoint data page " << page << " was corrupt"); +} + bool get_ipod_igsc_checkpoint(ipod_device_ptr_ref_t p_ipod, pfc::array_t & p_out) { try @@ -59,33 +109,27 @@ bool get_ipod_igsc_checkpoint(ipod_device_ptr_ref_t p_ipod, pfc::array_tdriver_symbolic_path.get_ptr(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL)); if (!p_volume.is_valid()) throw pfc::exception(pfc::string8() << "CreateFile failed: " << format_win32_error(GetLastError())); - io_ctrl_igsc<0x1000> data; - memset(&data, 0, sizeof(data)); - data.v0 = -64; - data.v1 = 64; - data.v2 = 2; - data.v3 = 0; - data.v4 = 0x1000; + uint8_t page{}; + bool more_data_exists{true}; - while (true) - { - if (!DeviceIoControl(p_volume, 0x2200A0, &data, sizeof(data), &data, sizeof(data), &returned, NULL)) - break; - if (returned <= 8) break; - p_out.append_fromptr(data.m_buffer, returned - 8); - if (returned < 0x1008) break; - data.v3++; + while (more_data_exists) { + auto&& [page_data, more_data_exists_] = get_igsc_checkpoint_page(p_volume, page); + more_data_exists = more_data_exists_; + p_out.append_fromptr(page_data.data(), page_data.size()); + page++; } p_volume.release(); } - catch (pfc::exception const &) { return false; } + catch (pfc::exception const & ex) { + console::formatter formatter; + formatter << "Failed getting checkpoint data via iGSC: " << ex.what() << ". This is normal for very old iPod models."; + return false; + } return p_out.get_size() > 150; } From f42f6a18beee421998af72427ad7d6afa7d70a2a Mon Sep 17 00:00:00 2001 From: Reupen Shah Date: Wed, 20 Jun 2018 20:24:19 +0100 Subject: [PATCH 3/3] Update flags used when opening volume for iGSC checkpoint querying --- foo_dop/device_info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foo_dop/device_info.cpp b/foo_dop/device_info.cpp index 477fa07..bcbd951 100644 --- a/foo_dop/device_info.cpp +++ b/foo_dop/device_info.cpp @@ -109,7 +109,7 @@ bool get_ipod_igsc_checkpoint(ipod_device_ptr_ref_t p_ipod, pfc::array_tdriver_symbolic_path.get_ptr(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL)); + p_volume.set(CreateFile(p_ipod->driver_symbolic_path.get_ptr(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL)); if (!p_volume.is_valid()) throw pfc::exception(pfc::string8() << "CreateFile failed: " << format_win32_error(GetLastError()));