]> FriiDump Source - friidump.git/blobdiff - libfriidump/xbox_ref/utils.c
FriiDump 0.5.3.15: close XGD1 geometry and lead-in capture
[friidump.git] / libfriidump / xbox_ref / utils.c
index 2e24078c86395157d7bf360335635c808618ce8a..c63b03bedb6aef1afa5d739592ecd0f2cedefac6 100644 (file)
@@ -3,6 +3,7 @@
 #include "xbe_cert.h"
 #include "unlock.h"
 #include "xbox_ref_log.h"
 #include "xbe_cert.h"
 #include "unlock.h"
 #include "xbox_ref_log.h"
+#include "../xbox_ref_bridge.h"
 
 #include <time.h>
 #include <windows.h>
 
 #include <time.h>
 #include <windows.h>
@@ -1980,7 +1981,7 @@ static void JsonWriteValidationWarnings(FILE *f, const XboxDvdSidecarCapture *ca
     if (!payloadFilesPresent)
         WRITE_WARNING("payload_files_not_fully_present");
     if (redumpStyleZeroFilledPadding)
     if (!payloadFilesPresent)
         WRITE_WARNING("payload_files_not_fully_present");
     if (redumpStyleZeroFilledPadding)
-        WRITE_WARNING("redump_style_padding_zero_filled_pending_hardware_capture");
+        WRITE_WARNING("redump_style_padding_zero_filled_unresolved_content");
 
 #undef WRITE_WARNING
 
 
 #undef WRITE_WARNING
 
@@ -2475,6 +2476,9 @@ static BOOL WriteXboxDvdMediaProfileFile(const char *isoFilename,
         fprintf(json, "    \"pregame_padding_start_lba\": %u,\n", redumpStyle ? XGD1_VIDEO_L0_SECTORS : 0U);
         fprintf(json, "    \"pregame_padding_sector_count\": %u,\n", redumpStyle ? (XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) : 0U);
         fprintf(json, "    \"game_output_start_lba\": %u,\n", gameOutputLba);
         fprintf(json, "    \"pregame_padding_start_lba\": %u,\n", redumpStyle ? XGD1_VIDEO_L0_SECTORS : 0U);
         fprintf(json, "    \"pregame_padding_sector_count\": %u,\n", redumpStyle ? (XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) : 0U);
         fprintf(json, "    \"game_output_start_lba\": %u,\n", gameOutputLba);
+        fprintf(json, "    \"game_leadin_unlocked_source_start_lba\": %u,\n", redumpStyle ? 0U : gameSourceLba);
+        fprintf(json, "    \"game_leadin_source_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
+        fprintf(json, "    \"game_leadin_source\": "); JsonWriteEscapedString(json, redumpStyle ? "drive_read10" : "not_applicable"); fprintf(json, ",\n");
         fprintf(json, "    \"game_unlocked_source_start_lba\": %u,\n", gameSourceLba);
         fprintf(json, "    \"game_unlocked_source_sector_count\": %u,\n", redumpStyle ? XGD1_GAME_SOURCE_SECTORS : gameSectors);
         fprintf(json, "    \"game_xiso_leadin_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
         fprintf(json, "    \"game_unlocked_source_start_lba\": %u,\n", gameSourceLba);
         fprintf(json, "    \"game_unlocked_source_sector_count\": %u,\n", redumpStyle ? XGD1_GAME_SOURCE_SECTORS : gameSectors);
         fprintf(json, "    \"game_xiso_leadin_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
@@ -2493,10 +2497,12 @@ static BOOL WriteXboxDvdMediaProfileFile(const char *isoFilename,
 
     fprintf(json, "  \"reconstruction\": {\n");
     fprintf(json, "    \"is_reconstructed_layout\": %s,\n", redumpStyle ? "true" : "false");
 
     fprintf(json, "  \"reconstruction\": {\n");
     fprintf(json, "    \"is_reconstructed_layout\": %s,\n", redumpStyle ? "true" : "false");
-    fprintf(json, "    \"filler_policy\": "); JsonWriteEscapedString(json, redumpStyle ? "zero_fill_until_drive_can_read_filler" : "not_applicable"); fprintf(json, ",\n");
+    fprintf(json, "    \"filler_policy\": "); JsonWriteEscapedString(json, redumpStyle ? "pregame_and_postgame_zero_fill_content_placeholder" : "not_applicable"); fprintf(json, ",\n");
+    fprintf(json, "    \"filler_geometry_verified\": %s,\n", redumpStyle ? "true" : "false");
     fprintf(json, "    \"filler_verified_from_disc\": false,\n");
     fprintf(json, "    \"filler_byte_value\": %s,\n", redumpStyle ? "0" : "null");
     fprintf(json, "    \"filler_verified_from_disc\": false,\n");
     fprintf(json, "    \"filler_byte_value\": %s,\n", redumpStyle ? "0" : "null");
-    fprintf(json, "    \"pending_hardware_capture\": %s,\n", redumpStyle ? "true" : "false");
+    fprintf(json, "    \"pending_hardware_capture\": false,\n");
+    fprintf(json, "    \"unresolved_filler_content\": %s,\n", redumpStyle ? "true" : "false");
     fprintf(json, "    \"filler_ranges\": [\n");
     if (redumpStyle)
     {
     fprintf(json, "    \"filler_ranges\": [\n");
     if (redumpStyle)
     {
@@ -2514,7 +2520,7 @@ static BOOL WriteXboxDvdMediaProfileFile(const char *isoFilename,
         fprintf(json, "      }\n");
     }
     fprintf(json, "    ],\n");
         fprintf(json, "      }\n");
     }
     fprintf(json, "    ],\n");
-    fprintf(json, "    \"note\": \"Padding/filler ranges are intentionally zero-filled placeholders until a drive/workflow capable of reading those regions is available.\"\n");
+    fprintf(json, "    \"note\": \"Pregame and postgame physical locations are verified by cache-aligned raw sector IDs, but their inaccessible contents remain zero-filled placeholders. The 32-sector game lead-in is drive-captured from unlocked LBA 0..31.\"\n");
     fprintf(json, "  },\n");
 
     fprintf(json, "  \"dvd_structures\": {\n");
     fprintf(json, "  },\n");
 
     fprintf(json, "  \"dvd_structures\": {\n");
@@ -2627,6 +2633,9 @@ static BOOL WriteXboxDvdSidecarFiles(const char *isoFilename,
         fprintf(json, "      \"pregame_padding_start_lba\": %u,\n", redumpStyle ? XGD1_VIDEO_L0_SECTORS : 0U);
         fprintf(json, "      \"pregame_padding_sector_count\": %u,\n", redumpStyle ? (XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) : 0U);
         fprintf(json, "      \"game_output_start_lba\": %u,\n", gameOutputLba);
         fprintf(json, "      \"pregame_padding_start_lba\": %u,\n", redumpStyle ? XGD1_VIDEO_L0_SECTORS : 0U);
         fprintf(json, "      \"pregame_padding_sector_count\": %u,\n", redumpStyle ? (XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) : 0U);
         fprintf(json, "      \"game_output_start_lba\": %u,\n", gameOutputLba);
+        fprintf(json, "      \"game_leadin_unlocked_source_start_lba\": %u,\n", redumpStyle ? 0U : gameSourceLba);
+        fprintf(json, "      \"game_leadin_source_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
+        fprintf(json, "      \"game_leadin_source\": "); JsonWriteEscapedString(json, redumpStyle ? "drive_read10" : "not_applicable"); fprintf(json, ",\n");
         fprintf(json, "      \"game_unlocked_source_start_lba\": %u,\n", gameSourceLba);
         fprintf(json, "      \"game_unlocked_source_sector_count\": %u,\n", redumpStyle ? XGD1_GAME_SOURCE_SECTORS : gameSectors);
         fprintf(json, "      \"game_xiso_leadin_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
         fprintf(json, "      \"game_unlocked_source_start_lba\": %u,\n", gameSourceLba);
         fprintf(json, "      \"game_unlocked_source_sector_count\": %u,\n", redumpStyle ? XGD1_GAME_SOURCE_SECTORS : gameSectors);
         fprintf(json, "      \"game_xiso_leadin_sector_count\": %u,\n", redumpStyle ? XGD1_XISO_LEADIN_SECTORS : 0U);
@@ -2695,7 +2704,10 @@ static BOOL WriteXboxDvdSidecarFiles(const char *isoFilename,
     fprintf(json, "  ],\n");
 
     fprintf(json, "  \"auth\": {\n");
     fprintf(json, "  ],\n");
 
     fprintf(json, "  \"auth\": {\n");
-    fprintf(json, "    \"requires_media_transition\": true,\n");
+    fprintf(json, "    \"requires_media_transition\": false,\n");
+    fprintf(json, "    \"unlock_requires_media_transition\": false,\n");
+    fprintf(json, "    \"locked_video_view_restore_requires_media_transition\": true,\n");
+    fprintf(json, "    \"state_detection\": \"READ CAPACITY (10) visible-sector count\",\n");
     fprintf(json, "    \"mode_page\": \"0x3E\",\n");
     fprintf(json, "    \"challenge_table_source\": \"read_dvd_structure_xbox_control_block\",\n");
     fprintf(json, "    \"challenge_table_response_offset\": 774,\n");
     fprintf(json, "    \"mode_page\": \"0x3E\",\n");
     fprintf(json, "    \"challenge_table_source\": \"read_dvd_structure_xbox_control_block\",\n");
     fprintf(json, "    \"challenge_table_response_offset\": 774,\n");
@@ -2734,7 +2746,7 @@ static BOOL WriteXboxDvdSidecarFiles(const char *isoFilename,
     return ok;
 }
 
     return ok;
 }
 
-void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uint32_t totalDiscSectors, bool isDualLayer, bool EjectOnSuccess)
+BOOL DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uint32_t totalDiscSectors, bool isDualLayer, bool EjectOnSuccess, xbox_ref_dump_result *result)
 {
     HCRYPTPROV hProv = 0;
     HCRYPTHASH hHash = 0;
 {
     HCRYPTPROV hProv = 0;
     HCRYPTHASH hHash = 0;
@@ -2760,6 +2772,15 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
 
     memset(&sidecarCapture, 0, sizeof(sidecarCapture));
 
 
     memset(&sidecarCapture, 0, sizeof(sidecarCapture));
 
+    if (result) {
+        result->attempted = 1;
+        result->mode = xisoFormat;
+        if (filename && filename[0]) {
+            strncpy(result->output_path, filename, sizeof(result->output_path) - 1);
+            result->output_path[sizeof(result->output_path) - 1] = '\0';
+        }
+    }
+
     if (totalDiscSectors == 0)
         totalDiscSectors = GetTotalSectors(hDevice);
     if (totalDiscSectors == 0)
     if (totalDiscSectors == 0)
         totalDiscSectors = GetTotalSectors(hDevice);
     if (totalDiscSectors == 0)
@@ -2768,11 +2789,11 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
     rawTargetSectors = NormalizeRawIsoTargetSectors(totalDiscSectors, isDualLayer);
 
     if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
     rawTargetSectors = NormalizeRawIsoTargetSectors(totalDiscSectors, isDualLayer);
 
     if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
-        return;
+        return FALSE;
     if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
     {
         CryptReleaseContext(hProv, 0);
     if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
     {
         CryptReleaseContext(hProv, 0);
-        return;
+        return FALSE;
     }
 
     EnsureDriveReady(hDevice, 30000);
     }
 
     EnsureDriveReady(hDevice, 30000);
@@ -2788,6 +2809,8 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
 
         outputLabel = "RAW ISO";
         expectedOutputBytes = (unsigned long long)rawTargetSectors * 2048ULL;
 
         outputLabel = "RAW ISO";
         expectedOutputBytes = (unsigned long long)rawTargetSectors * 2048ULL;
+        if (result)
+            result->output_sectors = rawTargetSectors;
 
         if (rawTargetSectors != totalDiscSectors)
         {
 
         if (rawTargetSectors != totalDiscSectors)
         {
@@ -2926,20 +2949,28 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
                 printf("[WARN] XDFS was detected at unlocked source LBA %u, not the expected XISO header LBA 32.\n", detectedXdfsLba);
             }
 
                 printf("[WARN] XDFS was detected at unlocked source LBA %u, not the expected XISO header LBA 32.\n", detectedXdfsLba);
             }
 
-            // Build the Redump-style XISO/game region using the same proven
-            // convention as option 2: the first 32 sectors are synthetic XISO
-            // lead-in/padding, and the real XDFS volume begins at source LBA 32.
-            // Do not read unlocked source LBA 0..31 here; on the 8050L path those
-            // LBAs are not the XDFS header sectors we want in the rebuilt image.
+            // FriiDump 0.5.3.13 cache-aligned raw-ID validation proved that
+            // unlocked source LBA 0..31 is the physical 32-sector game-region
+            // lead-in and that XDVDFS begins at source LBA 32. Preserve the
+            // drive-captured lead-in instead of synthesizing zero sectors.
             gameSourceLba = XGD1_GAME_SOURCE_START_LBA;
             gameSectors = REDUMP_SECTORS;
             rawVideoSectors = XGD1_GAME_OUTPUT_START_LBA;
             rawGameSourceLba = gameSourceLba;
             rawGameSectors = gameSectors;
 
             gameSourceLba = XGD1_GAME_SOURCE_START_LBA;
             gameSectors = REDUMP_SECTORS;
             rawVideoSectors = XGD1_GAME_OUTPUT_START_LBA;
             rawGameSourceLba = gameSourceLba;
             rawGameSectors = gameSectors;
 
-            printf("[RAW] Writing %u-sector XISO lead-in/padding at output LBA %u.\n",
-                   XGD1_XISO_LEADIN_SECTORS, XGD1_GAME_OUTPUT_START_LBA);
-            if (!WriteZeroSectorsOutput(outFile, hHash, XGD1_XISO_LEADIN_SECTORS, XGD1_GAME_OUTPUT_START_LBA, "GAME-XISO-LEADIN"))
+            printf("[RAW] Capturing %u-sector game lead-in from unlocked source LBA 0..%u at output LBA %u.\n",
+                   XGD1_XISO_LEADIN_SECTORS,
+                   XGD1_XISO_LEADIN_SECTORS - 1,
+                   XGD1_GAME_OUTPUT_START_LBA);
+            if (!DumpSectorRangeWithRetry(hDevice,
+                                          outFile,
+                                          hHash,
+                                          0,
+                                          XGD1_XISO_LEADIN_SECTORS,
+                                          XGD1_GAME_OUTPUT_START_LBA,
+                                          "GAME-XISO-LEADIN",
+                                          TRUE))
             {
                 VirtualFree(videoL1Buffer, 0, MEM_RELEASE);
                 goto cleanup;
             {
                 VirtualFree(videoL1Buffer, 0, MEM_RELEASE);
                 goto cleanup;
@@ -3061,6 +3092,8 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
 
         outputLabel = "XISO";
         expectedOutputBytes = ((unsigned long long)sectorsToRead + 32ULL) * 2048ULL;
 
         outputLabel = "XISO";
         expectedOutputBytes = ((unsigned long long)sectorsToRead + 32ULL) * 2048ULL;
+        if (result)
+            result->output_sectors = sectorsToRead + 32U;
 
         printf("[SUCCESS] Final XISO target: %u sectors plus 32-sector lead-in (%llu bytes).\n",
                sectorsToRead,
 
         printf("[SUCCESS] Final XISO target: %u sectors plus 32-sector lead-in (%llu bytes).\n",
                sectorsToRead,
@@ -3150,6 +3183,19 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
         printf("\n[WARN] Could not calculate CRC32/MD5/SHA-1/SHA-256 from finalized output file.\n");
     }
 
         printf("\n[WARN] Could not calculate CRC32/MD5/SHA-1/SHA-256 from finalized output file.\n");
     }
 
+    if (result) {
+        result->output_size = GetFileSizeBytes64(filename);
+        strncpy(result->crc32, crc32String, sizeof(result->crc32) - 1);
+        result->crc32[sizeof(result->crc32) - 1] = '\0';
+        strncpy(result->md5, md5String, sizeof(result->md5) - 1);
+        result->md5[sizeof(result->md5) - 1] = '\0';
+        strncpy(result->sha1, sha1String, sizeof(result->sha1) - 1);
+        result->sha1[sizeof(result->sha1) - 1] = '\0';
+        strncpy(result->sha256, fileSha256String, sizeof(result->sha256) - 1);
+        result->sha256[sizeof(result->sha256) - 1] = '\0';
+        result->hashes_complete = result->crc32[0] && result->md5[0] && result->sha1[0] && result->sha256[0];
+    }
+
     if (xisoFormat == '1')
     {
         printf("Final RAW ISO Sector Count: %u\n", rawTargetSectors);
     if (xisoFormat == '1')
     {
         printf("Final RAW ISO Sector Count: %u\n", rawTargetSectors);
@@ -3192,8 +3238,9 @@ void DumpXboxGameDisc(HANDLE hDevice, const char *filename, char xisoFormat, uin
     FormatElapsedTime(GetTickCount() - operationStartTick, operationTimeStr);
     printf("\nOperation Complete! Total elapsed: %s\n", operationTimeStr);
 
     FormatElapsedTime(GetTickCount() - operationStartTick, operationTimeStr);
     printf("\nOperation Complete! Total elapsed: %s\n", operationTimeStr);
 
-    StopDriveUnit(hDevice);
-
+    /* The caller owns final drive cleanup.  Embedded FriiDump runs issue one
+     * STOP UNIT after Redump verification; standalone bridge runs stop the
+     * drive in xbox_ref_gdr8050l_dump_core() before closing the handle. */
     if (EjectOnSuccess)
         ControlTray(hDevice, TRUE);
 
     if (EjectOnSuccess)
         ControlTray(hDevice, TRUE);
 
@@ -3204,4 +3251,11 @@ cleanup:
         CryptDestroyHash(hHash);
     if (hProv)
         CryptReleaseContext(hProv, 0);
         CryptDestroyHash(hHash);
     if (hProv)
         CryptReleaseContext(hProv, 0);
+    if (result) {
+        result->dump_success = dumpOk ? 1 : 0;
+        result->elapsed_seconds = (double)(GetTickCount() - operationStartTick) / 1000.0;
+        if (dumpOk && result->output_size == 0)
+            result->output_size = GetFileSizeBytes64(filename);
+    }
+    return dumpOk;
 }
 }