#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;
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;
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;
}
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;
}
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);
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));
}
}
+ 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");
}
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)
} 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;
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