]> FriiDump Source - friidump.git/blob - libfriidump/xbox_ref_bridge.c
a120c28676b909e63a8e58e10c931f123b89ad80
[friidump.git] / libfriidump / xbox_ref_bridge.c
1 #include "xbox_ref_bridge.h"
2
3 #ifdef WIN32
4 #define WIN32_LEAN_AND_MEAN
5 #define _WIN32_WINNT 0x0500
6 #include <windows.h>
7 #include <winioctl.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include "xbox_ref/utils.h"
11 #include "xbox_ref/unlock.h"
12 #include "xbox_ref/xbox_ref_log.h"
13
14 #define printf xbox_ref_printf
15
16 static char xbox_ref_drive_letter_from_device(const char *device)
17 {
18     if (!device || !device[0]) return 0;
19     if (device[0] && device[1] == ':') return device[0];
20     if (device[0] == '\\' && device[1] == '\\' && device[2] == '.' && device[3] == '\\' && device[4] && device[5] == ':') return device[4];
21     return device[0];
22 }
23
24 static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const char *filename, char mode, BOOL ownsHandle)
25 {
26     char driveLetter;
27     XboxGameInfo game;
28     BOOL isDualLayer = FALSE;
29     bool isDualLayerBool = false;
30     char mediaId[33] = {0};
31     char finalFilename[MAX_PATH] = {0};
32     BOOL filenameOverride;
33     uint32_t totalSectors = 0;
34     DWORD dwBytesReturned = 0;
35     BOOL volumeLocked = FALSE;
36     BOOL ok = FALSE;
37
38     filenameOverride = (filename && filename[0]);
39
40     if (mode != '1' && mode != '2') {
41         xbox_ref_log_open_for_target(filename, 0);
42         printf("[XBOX-REF] Fatal: unsupported Xbox reference dump mode '%c'.\n", mode);
43         xbox_ref_log_close();
44         return 1;
45     }
46
47     driveLetter = xbox_ref_drive_letter_from_device(device);
48     if (!driveLetter) {
49         xbox_ref_log_open_for_target(filename, 0);
50         printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
51         xbox_ref_log_close();
52         return 1;
53     }
54
55     xbox_ref_log_open_for_target(filename, driveLetter);
56     printf("[XBOX-REF] Using copied original GDR-8050L dumper flow for drive %c:.\n", driveLetter);
57     printf("[XBOX-REF] Handle mode: %s.\n", ownsHandle ? "opened by xbox_ref wrapper" : "using FriiDump's existing drive HANDLE");
58     printf("[XBOX-REF] Preserving reference timing sleeps: tray 3000ms, ready-settle 1500ms/10000ms fallback, RefreshVolume 1000ms + post-refresh 2000ms.\n");
59
60     if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
61         printf("[XBOX-REF] Fatal: invalid drive handle for %c:.\n", driveLetter);
62         goto cleanup;
63     }
64
65     printf("Opening drive %c: for Atomic Handshake...\n", driveLetter);
66     EnsureDriveReady(hDevice, 30000);
67     UnlockDrive(hDevice);
68
69     AutomateTrayCycle(hDevice);
70
71     printf("Re-applying 8050L Handshake after Media Change...\n");
72     UnlockDrive(hDevice);
73
74     RefreshVolume(hDevice);
75     Sleep(2000);
76     EnsureDriveReady(hDevice, 30000);
77
78     printf("Setting drive to maximum performance mode...\n");
79     SetDriveSpeedMax(hDevice);
80
81     if (!DeviceIoControl(hDevice, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) {
82         printf("[!] Warning: Could not lock volume. Close any open folders pointing to the drive.\n");
83         printf("[XBOX-REF] The reference dumper treats this as fatal before XBE/title probing.\n");
84         goto cleanup;
85     }
86     volumeLocked = TRUE;
87
88     printf("Searching for Xbox Game Signature (Raw SCSI Scan)...\n");
89     game = GetXboxGameInfo(hDevice);
90     printf("Game Title Raw: %s\n", game.TitleName);
91     ReadXboxGameDir(hDevice);
92
93     totalSectors = GetXboxPhysicalSectors(hDevice);
94     isDualLayerBool = false;
95     GetDiscMetadata(hDevice, &totalSectors, &isDualLayerBool, &game);
96     isDualLayer = isDualLayerBool ? TRUE : FALSE;
97     GetMediaID(hDevice, mediaId);
98
99     if (game.Success) {
100         char titleCopy[sizeof(game.TitleName)];
101         memset(titleCopy, 0, sizeof(titleCopy));
102         strncpy(titleCopy, game.TitleName, sizeof(titleCopy) - 1);
103         SanitizeFilename(titleCopy);
104         if (filenameOverride) {
105             strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
106             finalFilename[sizeof(finalFilename) - 1] = '\0';
107             printf("[XBOX-REF] Output filename override: %s\n", finalFilename);
108         } else {
109             snprintf(finalFilename, sizeof(finalFilename), "%s[%s].%s",
110                      titleCopy[0] ? titleCopy : "XboxDisc",
111                      mediaId[0] ? mediaId : "UNKNOWN_ID",
112                      (mode == '1') ? "iso" : "xiso");
113             printf("[XBOX-REF] XBE/DMI-derived output filename: %s\n", finalFilename);
114             xbox_ref_log_retarget(finalFilename);
115         }
116         DisplayXboxGameInfo(game);
117         printf("\n--- DISC INFORMATION ---\n");
118         printf("Physical Sectors: %u\n", totalSectors);
119         printf("Layers:           %d\n", isDualLayer ? 2 : 1);
120         printf("Media ID:         %s\n", mediaId);
121         printf("Target File:      %s\n", finalFilename);
122         printf("-------------------------------\n\n");
123     } else {
124         if (filenameOverride) {
125             strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
126             finalFilename[sizeof(finalFilename) - 1] = '\0';
127             printf("Error: Could not retrieve Xbox game information; using override filename %s.\n", finalFilename);
128         } else {
129             printf("Error: Could not retrieve Xbox game information and no output filename override was supplied.\n");
130             printf("       Rerun with -i <file> or -X <file> if metadata probing cannot complete.\n");
131             goto cleanup;
132         }
133     }
134
135     if (totalSectors != (uint32_t)(REDUMP_SECTORS)) {
136         printf("[WARNING] Unlocked drive-reported sectors: %u does not match expected Xbox game-view sectors: %u\n", totalSectors, (uint32_t)(REDUMP_SECTORS));
137         printf("-Homebrew games may have different sizes.\n\n");
138     }
139
140     if (totalSectors == 0) {
141         printf("Error: Could not determine total sectors for dumping.\n");
142         goto cleanup;
143     }
144
145     printf("Starting dump with copied DumpXboxGameDisc() mode %c...\n", mode);
146     DumpXboxGameDisc(hDevice, finalFilename, mode, totalSectors, isDualLayerBool, FALSE);
147     ok = TRUE;
148
149 cleanup:
150     if (volumeLocked)
151         DeviceIoControl(hDevice, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
152     if (ownsHandle && hDevice != INVALID_HANDLE_VALUE && hDevice != NULL) {
153         printf("Issuing STOP UNIT / spin-down after dump attempt... ");
154         if (StopDriveUnit(hDevice)) printf("OK\n"); else printf("FAILED\n");
155         CloseDrive(hDevice);
156     } else {
157         printf("[XBOX-REF] Returning to FriiDump; final STOP UNIT cleanup will use the same handle.\n");
158     }
159     printf("[XBOX-REF] Log file complete: %s\n", xbox_ref_log_path() ? xbox_ref_log_path() : "(unavailable)");
160     xbox_ref_log_close();
161     return ok ? 0 : 1;
162 }
163
164 int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode)
165 {
166     return xbox_ref_gdr8050l_dump_core((HANDLE)native_handle, device, filename, mode, FALSE);
167 }
168
169 int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode)
170 {
171     char driveLetter;
172     HANDLE hDevice;
173
174     driveLetter = xbox_ref_drive_letter_from_device(device);
175     if (!driveLetter) {
176         xbox_ref_log_open_for_target(filename, 0);
177         printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
178         xbox_ref_log_close();
179         return 1;
180     }
181
182     hDevice = OpenDrive(driveLetter);
183     if (hDevice == INVALID_HANDLE_VALUE) {
184         xbox_ref_log_open_for_target(filename, driveLetter);
185         printf("[XBOX-REF] Fatal: Cannot open drive %c:. Run as Administrator.\n", driveLetter);
186         xbox_ref_log_close();
187         return 1;
188     }
189
190     return xbox_ref_gdr8050l_dump_core(hDevice, device, filename, mode, TRUE);
191 }
192 #else
193 int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode)
194 {
195     (void)native_handle; (void)device; (void)filename; (void)mode; return 1;
196 }
197
198 int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode)
199 {
200     (void)device; (void)filename; (void)mode; return 1;
201 }
202 #endif