]> FriiDump Source - friidump.git/blob - libfriidump/xbox_ref_bridge.c
663805d10f0e04d8c842e2569124734a5c57382b
[friidump.git] / libfriidump / xbox_ref_bridge.c
1 #include "xbox_ref_bridge.h"
2
3 #include <string.h>
4
5 void xbox_ref_dump_result_init(xbox_ref_dump_result *result)
6 {
7     if (result)
8         memset(result, 0, sizeof(*result));
9 }
10
11 #ifdef WIN32
12 #define WIN32_LEAN_AND_MEAN
13 #define _WIN32_WINNT 0x0500
14 #include <windows.h>
15 #include <winioctl.h>
16 #include <stdio.h>
17 #include "xbox_ref/utils.h"
18 #include "xbox_ref/unlock.h"
19 #include "xbox_ref/xbox_ref_log.h"
20
21 #define printf xbox_ref_printf
22
23 #define XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS 200000U
24
25 static BOOL xbox_ref_capacity_is_game_view(uint32_t sectors)
26 {
27     return sectors > XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS;
28 }
29
30 static uint32_t xbox_ref_refresh_ready_capacity(HANDLE hDevice)
31 {
32     RefreshVolume(hDevice);
33     Sleep(2000);
34     EnsureDriveReady(hDevice, 30000);
35     return GetTotalSectors(hDevice);
36 }
37
38 static char xbox_ref_drive_letter_from_device(const char *device)
39 {
40     if (!device || !device[0]) return 0;
41     if (device[0] && device[1] == ':') return device[0];
42     if (device[0] == '\\' && device[1] == '\\' && device[2] == '.' && device[3] == '\\' && device[4] && device[5] == ':') return device[4];
43     return device[0];
44 }
45
46 static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const char *filename, char mode, BOOL ownsHandle, xbox_ref_dump_result *result)
47 {
48     char driveLetter;
49     XboxGameInfo game;
50     BOOL isDualLayer = FALSE;
51     bool isDualLayerBool = false;
52     char mediaId[33] = {0};
53     char finalFilename[MAX_PATH] = {0};
54     BOOL filenameOverride;
55     uint32_t totalSectors = 0;
56     DWORD dwBytesReturned = 0;
57     BOOL volumeLocked = FALSE;
58     BOOL ok = FALSE;
59
60     xbox_ref_dump_result_init(result);
61     if (result) {
62         result->attempted = 1;
63         result->mode = mode;
64     }
65
66     filenameOverride = (filename && filename[0]);
67
68     if (mode != '1' && mode != '2') {
69         xbox_ref_log_open_for_target(filename, 0);
70         printf("[XBOX-REF] Fatal: unsupported Xbox reference dump mode '%c'.\n", mode);
71         if (ownsHandle)
72             xbox_ref_log_close();
73         return 1;
74     }
75
76     driveLetter = xbox_ref_drive_letter_from_device(device);
77     if (!driveLetter) {
78         xbox_ref_log_open_for_target(filename, 0);
79         printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
80         if (ownsHandle)
81             xbox_ref_log_close();
82         return 1;
83     }
84
85     xbox_ref_log_open_for_target(filename, driveLetter);
86     printf("[XBOX-REF] Using copied original GDR-8050L dumper flow for drive %c:.\n", driveLetter);
87     printf("[XBOX-REF] Handle mode: %s.\n", ownsHandle ? "opened by xbox_ref wrapper" : "using FriiDump's existing drive HANDLE");
88     printf("[XBOX-REF] Preserving reference timing sleeps: tray 3000ms, ready-settle 1500ms/10000ms fallback, RefreshVolume 1000ms + post-refresh 2000ms.\n");
89
90     if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
91         printf("[XBOX-REF] Fatal: invalid drive handle for %c:.\n", driveLetter);
92         goto cleanup;
93     }
94
95     {
96         uint32_t entrySectors;
97         uint32_t verifiedSectors;
98         BOOL preparedAfterHandshake = FALSE;
99
100         printf("Opening drive %c: for state-aware Xbox handshake...\n", driveLetter);
101         if (!EnsureDriveReady(hDevice, 30000)) {
102             printf("[XBOX-REF] Fatal: drive did not become ready before Xbox state preparation.\n");
103             goto cleanup;
104         }
105
106         entrySectors = GetTotalSectors(hDevice);
107         printf("[XBOX-REF] Entry READ CAPACITY: %u sectors.\n", entrySectors);
108
109         if (xbox_ref_capacity_is_game_view(entrySectors)) {
110             printf("[XBOX-REF] Entry state already exposes the Xbox game view; skipping the redundant initial handshake and tray cycle.\n");
111         } else {
112             printf("[XBOX-REF] Entry state appears locked/video; attempting the full handshake directly without a media transition.\n");
113             UnlockDrive(hDevice);
114             verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
115             preparedAfterHandshake = TRUE;
116             printf("[XBOX-REF] Direct-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);
117
118             if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
119                 printf("[XBOX-REF][WARN] Direct handshake did not expose the Xbox game view; performing one tray-cycle recovery and retry.\n");
120                 AutomateTrayCycle(hDevice);
121                 printf("[XBOX-REF] Re-applying the full handshake after recovery media change.\n");
122                 UnlockDrive(hDevice);
123                 verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
124                 printf("[XBOX-REF] Recovery-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);
125
126                 if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
127                     printf("[XBOX-REF] Fatal: Xbox game view was not established after direct and recovery handshakes.\n");
128                     goto cleanup;
129                 }
130             }
131         }
132
133         if (!preparedAfterHandshake)
134             xbox_ref_refresh_ready_capacity(hDevice);
135     }
136
137     printf("Setting drive to maximum performance mode...\n");
138     SetDriveSpeedMax(hDevice);
139
140     if (!DeviceIoControl(hDevice, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) {
141         printf("[!] Warning: Could not lock volume. Close any open folders pointing to the drive.\n");
142         printf("[XBOX-REF] The reference dumper treats this as fatal before XBE/title probing.\n");
143         goto cleanup;
144     }
145     volumeLocked = TRUE;
146
147     printf("Searching for Xbox Game Signature (Raw SCSI Scan)...\n");
148     game = GetXboxGameInfo(hDevice);
149     printf("Game Title Raw: %s\n", game.TitleName);
150     ReadXboxGameDir(hDevice);
151
152     totalSectors = GetXboxPhysicalSectors(hDevice);
153     isDualLayerBool = false;
154     GetDiscMetadata(hDevice, &totalSectors, &isDualLayerBool, &game);
155     isDualLayer = isDualLayerBool ? TRUE : FALSE;
156     GetMediaID(hDevice, mediaId);
157
158     if (result) {
159         if (game.Success && game.TitleName[0]) {
160             strncpy(result->title, game.TitleName, sizeof(result->title) - 1);
161             result->title[sizeof(result->title) - 1] = '\0';
162         }
163         if (mediaId[0]) {
164             strncpy(result->media_id, mediaId, sizeof(result->media_id) - 1);
165             result->media_id[sizeof(result->media_id) - 1] = '\0';
166         }
167     }
168
169     if (game.Success) {
170         char titleCopy[sizeof(game.TitleName)];
171         memset(titleCopy, 0, sizeof(titleCopy));
172         strncpy(titleCopy, game.TitleName, sizeof(titleCopy) - 1);
173         SanitizeFilename(titleCopy);
174         if (filenameOverride) {
175             strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
176             finalFilename[sizeof(finalFilename) - 1] = '\0';
177             printf("[XBOX-REF] Output filename override: %s\n", finalFilename);
178         } else {
179             snprintf(finalFilename, sizeof(finalFilename), "%s[%s].%s",
180                      titleCopy[0] ? titleCopy : "XboxDisc",
181                      mediaId[0] ? mediaId : "UNKNOWN_ID",
182                      (mode == '1') ? "iso" : "xiso");
183             printf("[XBOX-REF] XBE/DMI-derived output filename: %s\n", finalFilename);
184             xbox_ref_log_retarget(finalFilename);
185         }
186         DisplayXboxGameInfo(game);
187         printf("\n--- DISC INFORMATION ---\n");
188         printf("Physical Sectors: %u\n", totalSectors);
189         printf("Layers:           %d\n", isDualLayer ? 2 : 1);
190         printf("Media ID:         %s\n", mediaId);
191         printf("Target File:      %s\n", finalFilename);
192         printf("-------------------------------\n\n");
193     } else {
194         if (filenameOverride) {
195             strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
196             finalFilename[sizeof(finalFilename) - 1] = '\0';
197             printf("Error: Could not retrieve Xbox game information; using override filename %s.\n", finalFilename);
198         } else {
199             printf("Error: Could not retrieve Xbox game information and no output filename override was supplied.\n");
200             printf("       Rerun with -i <file> or -X <file> if metadata probing cannot complete.\n");
201             goto cleanup;
202         }
203     }
204
205     if (result && finalFilename[0]) {
206         strncpy(result->output_path, finalFilename, sizeof(result->output_path) - 1);
207         result->output_path[sizeof(result->output_path) - 1] = '\0';
208     }
209
210     if (totalSectors != (uint32_t)(REDUMP_SECTORS)) {
211         printf("[WARNING] Unlocked drive-reported sectors: %u does not match expected Xbox game-view sectors: %u\n", totalSectors, (uint32_t)(REDUMP_SECTORS));
212         printf("-Homebrew games may have different sizes.\n\n");
213     }
214
215     if (totalSectors == 0) {
216         printf("Error: Could not determine total sectors for dumping.\n");
217         goto cleanup;
218     }
219
220     printf("Starting dump with copied DumpXboxGameDisc() mode %c...\n", mode);
221     ok = DumpXboxGameDisc(hDevice, finalFilename, mode, totalSectors, isDualLayerBool, FALSE, result);
222
223 cleanup:
224     if (volumeLocked)
225         DeviceIoControl(hDevice, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
226     if (ownsHandle && hDevice != INVALID_HANDLE_VALUE && hDevice != NULL) {
227         printf("Issuing STOP UNIT / spin-down after dump attempt... ");
228         if (StopDriveUnit(hDevice)) printf("OK\n"); else printf("FAILED\n");
229         CloseDrive(hDevice);
230     } else {
231         printf("[XBOX-REF] Returning to FriiDump; final STOP UNIT cleanup will use the same handle.\n");
232     }
233     if (ownsHandle) {
234         printf("[XBOX-REF] Log file complete: %s\n", xbox_ref_log_path() ? xbox_ref_log_path() : "(unavailable)");
235         xbox_ref_log_close();
236     } else if (ok) {
237         printf("[XBOX-REF] Returning finalized output evidence to FriiDump's shared Redump verifier.\n");
238     } else {
239         printf("[XBOX-REF] No completed output evidence is available for shared Redump verification.\n");
240     }
241     return ok ? 0 : 1;
242 }
243
244 int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
245 {
246     return xbox_ref_gdr8050l_dump_core((HANDLE)native_handle, device, filename, mode, FALSE, result);
247 }
248
249 int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
250 {
251     char driveLetter;
252     HANDLE hDevice;
253
254     driveLetter = xbox_ref_drive_letter_from_device(device);
255     if (!driveLetter) {
256         xbox_ref_log_open_for_target(filename, 0);
257         printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
258         xbox_ref_log_close();
259         return 1;
260     }
261
262     hDevice = OpenDrive(driveLetter);
263     if (hDevice == INVALID_HANDLE_VALUE) {
264         xbox_ref_log_open_for_target(filename, driveLetter);
265         printf("[XBOX-REF] Fatal: Cannot open drive %c:. Run as Administrator.\n", driveLetter);
266         xbox_ref_log_close();
267         return 1;
268     }
269
270     return xbox_ref_gdr8050l_dump_core(hDevice, device, filename, mode, TRUE, result);
271 }
272 #else
273 int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
274 {
275     (void)native_handle; (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
276 }
277
278 int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
279 {
280     (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
281 }
282 #endif