]> FriiDump Source - friidump.git/blobdiff - libfriidump/xbox_ref_bridge.c
FriiDump 0.5.3.10: add Redump evidence and optimize Xbox flow
[friidump.git] / libfriidump / xbox_ref_bridge.c
index a120c28676b909e63a8e58e10c931f123b89ad80..663805d10f0e04d8c842e2569124734a5c57382b 100644 (file)
@@ -1,18 +1,40 @@
 #include "xbox_ref_bridge.h"
 
+#include <string.h>
+
+void xbox_ref_dump_result_init(xbox_ref_dump_result *result)
+{
+    if (result)
+        memset(result, 0, sizeof(*result));
+}
+
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
 #define _WIN32_WINNT 0x0500
 #include <windows.h>
 #include <winioctl.h>
 #include <stdio.h>
-#include <string.h>
 #include "xbox_ref/utils.h"
 #include "xbox_ref/unlock.h"
 #include "xbox_ref/xbox_ref_log.h"
 
 #define printf xbox_ref_printf
 
+#define XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS 200000U
+
+static BOOL xbox_ref_capacity_is_game_view(uint32_t sectors)
+{
+    return sectors > XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS;
+}
+
+static uint32_t xbox_ref_refresh_ready_capacity(HANDLE hDevice)
+{
+    RefreshVolume(hDevice);
+    Sleep(2000);
+    EnsureDriveReady(hDevice, 30000);
+    return GetTotalSectors(hDevice);
+}
+
 static char xbox_ref_drive_letter_from_device(const char *device)
 {
     if (!device || !device[0]) return 0;
@@ -21,7 +43,7 @@ static char xbox_ref_drive_letter_from_device(const char *device)
     return device[0];
 }
 
-static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const char *filename, char mode, BOOL ownsHandle)
+static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const char *filename, char mode, BOOL ownsHandle, xbox_ref_dump_result *result)
 {
     char driveLetter;
     XboxGameInfo game;
@@ -35,12 +57,19 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
     BOOL volumeLocked = FALSE;
     BOOL ok = FALSE;
 
+    xbox_ref_dump_result_init(result);
+    if (result) {
+        result->attempted = 1;
+        result->mode = mode;
+    }
+
     filenameOverride = (filename && filename[0]);
 
     if (mode != '1' && mode != '2') {
         xbox_ref_log_open_for_target(filename, 0);
         printf("[XBOX-REF] Fatal: unsupported Xbox reference dump mode '%c'.\n", mode);
-        xbox_ref_log_close();
+        if (ownsHandle)
+            xbox_ref_log_close();
         return 1;
     }
 
@@ -48,7 +77,8 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
     if (!driveLetter) {
         xbox_ref_log_open_for_target(filename, 0);
         printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
-        xbox_ref_log_close();
+        if (ownsHandle)
+            xbox_ref_log_close();
         return 1;
     }
 
@@ -62,18 +92,47 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
         goto cleanup;
     }
 
-    printf("Opening drive %c: for Atomic Handshake...\n", driveLetter);
-    EnsureDriveReady(hDevice, 30000);
-    UnlockDrive(hDevice);
+    {
+        uint32_t entrySectors;
+        uint32_t verifiedSectors;
+        BOOL preparedAfterHandshake = FALSE;
 
-    AutomateTrayCycle(hDevice);
+        printf("Opening drive %c: for state-aware Xbox handshake...\n", driveLetter);
+        if (!EnsureDriveReady(hDevice, 30000)) {
+            printf("[XBOX-REF] Fatal: drive did not become ready before Xbox state preparation.\n");
+            goto cleanup;
+        }
 
-    printf("Re-applying 8050L Handshake after Media Change...\n");
-    UnlockDrive(hDevice);
+        entrySectors = GetTotalSectors(hDevice);
+        printf("[XBOX-REF] Entry READ CAPACITY: %u sectors.\n", entrySectors);
 
-    RefreshVolume(hDevice);
-    Sleep(2000);
-    EnsureDriveReady(hDevice, 30000);
+        if (xbox_ref_capacity_is_game_view(entrySectors)) {
+            printf("[XBOX-REF] Entry state already exposes the Xbox game view; skipping the redundant initial handshake and tray cycle.\n");
+        } else {
+            printf("[XBOX-REF] Entry state appears locked/video; attempting the full handshake directly without a media transition.\n");
+            UnlockDrive(hDevice);
+            verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
+            preparedAfterHandshake = TRUE;
+            printf("[XBOX-REF] Direct-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);
+
+            if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
+                printf("[XBOX-REF][WARN] Direct handshake did not expose the Xbox game view; performing one tray-cycle recovery and retry.\n");
+                AutomateTrayCycle(hDevice);
+                printf("[XBOX-REF] Re-applying the full handshake after recovery media change.\n");
+                UnlockDrive(hDevice);
+                verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
+                printf("[XBOX-REF] Recovery-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);
+
+                if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
+                    printf("[XBOX-REF] Fatal: Xbox game view was not established after direct and recovery handshakes.\n");
+                    goto cleanup;
+                }
+            }
+        }
+
+        if (!preparedAfterHandshake)
+            xbox_ref_refresh_ready_capacity(hDevice);
+    }
 
     printf("Setting drive to maximum performance mode...\n");
     SetDriveSpeedMax(hDevice);
@@ -96,6 +155,17 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
     isDualLayer = isDualLayerBool ? TRUE : FALSE;
     GetMediaID(hDevice, mediaId);
 
+    if (result) {
+        if (game.Success && game.TitleName[0]) {
+            strncpy(result->title, game.TitleName, sizeof(result->title) - 1);
+            result->title[sizeof(result->title) - 1] = '\0';
+        }
+        if (mediaId[0]) {
+            strncpy(result->media_id, mediaId, sizeof(result->media_id) - 1);
+            result->media_id[sizeof(result->media_id) - 1] = '\0';
+        }
+    }
+
     if (game.Success) {
         char titleCopy[sizeof(game.TitleName)];
         memset(titleCopy, 0, sizeof(titleCopy));
@@ -132,6 +202,11 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
         }
     }
 
+    if (result && finalFilename[0]) {
+        strncpy(result->output_path, finalFilename, sizeof(result->output_path) - 1);
+        result->output_path[sizeof(result->output_path) - 1] = '\0';
+    }
+
     if (totalSectors != (uint32_t)(REDUMP_SECTORS)) {
         printf("[WARNING] Unlocked drive-reported sectors: %u does not match expected Xbox game-view sectors: %u\n", totalSectors, (uint32_t)(REDUMP_SECTORS));
         printf("-Homebrew games may have different sizes.\n\n");
@@ -143,8 +218,7 @@ static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const
     }
 
     printf("Starting dump with copied DumpXboxGameDisc() mode %c...\n", mode);
-    DumpXboxGameDisc(hDevice, finalFilename, mode, totalSectors, isDualLayerBool, FALSE);
-    ok = TRUE;
+    ok = DumpXboxGameDisc(hDevice, finalFilename, mode, totalSectors, isDualLayerBool, FALSE, result);
 
 cleanup:
     if (volumeLocked)
@@ -156,17 +230,23 @@ cleanup:
     } else {
         printf("[XBOX-REF] Returning to FriiDump; final STOP UNIT cleanup will use the same handle.\n");
     }
-    printf("[XBOX-REF] Log file complete: %s\n", xbox_ref_log_path() ? xbox_ref_log_path() : "(unavailable)");
-    xbox_ref_log_close();
+    if (ownsHandle) {
+        printf("[XBOX-REF] Log file complete: %s\n", xbox_ref_log_path() ? xbox_ref_log_path() : "(unavailable)");
+        xbox_ref_log_close();
+    } else if (ok) {
+        printf("[XBOX-REF] Returning finalized output evidence to FriiDump's shared Redump verifier.\n");
+    } else {
+        printf("[XBOX-REF] No completed output evidence is available for shared Redump verification.\n");
+    }
     return ok ? 0 : 1;
 }
 
-int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode)
+int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
 {
-    return xbox_ref_gdr8050l_dump_core((HANDLE)native_handle, device, filename, mode, FALSE);
+    return xbox_ref_gdr8050l_dump_core((HANDLE)native_handle, device, filename, mode, FALSE, result);
 }
 
-int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode)
+int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
 {
     char driveLetter;
     HANDLE hDevice;
@@ -187,16 +267,16 @@ int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode)
         return 1;
     }
 
-    return xbox_ref_gdr8050l_dump_core(hDevice, device, filename, mode, TRUE);
+    return xbox_ref_gdr8050l_dump_core(hDevice, device, filename, mode, TRUE, result);
 }
 #else
-int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode)
+int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
 {
-    (void)native_handle; (void)device; (void)filename; (void)mode; return 1;
+    (void)native_handle; (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
 }
 
-int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode)
+int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
 {
-    (void)device; (void)filename; (void)mode; return 1;
+    (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
 }
 #endif