#include "dumper.h"
#include "unscrambler.h"
#include "xbox_ref/xbox_ref_log.h"
+#include "xbox_ref_bridge.h"
#include "redump_dat.h"
#ifdef WIN32
static bool g_redump_attempted = false;
static bool g_operation_duration_override_valid = false;
static double g_operation_duration_override = 0.0;
+static char g_executable_dir[1024];
static void friidump_summary_copy(char *dst, size_t dst_size, const char *src) {
if (!dst || dst_size == 0)
#define PACKAGE_NAME "FriiDump"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.5.3.10"
+#define PACKAGE_VERSION "0.5.3.15"
#ifdef WIN32
char *redump_dat_dir;
char *redump_report;
bool no_redump_verify;
+ bool xgd1_layout_probe;
+ char *xgd1_layout_probe_report;
+ bool xgd1_raw_id_probe;
+ char *xgd1_raw_id_probe_report;
} options;
static const char *friidump_requested_output_target(void) {
+ if (options.xgd1_raw_id_probe_report && options.xgd1_raw_id_probe_report[0]) return options.xgd1_raw_id_probe_report;
+ if (options.xgd1_layout_probe_report && options.xgd1_layout_probe_report[0]) return options.xgd1_layout_probe_report;
if (options.iso_out && options.iso_out[0]) return options.iso_out;
if (options.xiso_out && options.xiso_out[0]) return options.xiso_out;
if (options.raw_out && options.raw_out[0]) return options.raw_out;
+static void friidump_init_executable_dir(const char *argv0) {
+ char path[1024];
+ size_t length = 0;
+ char *slash;
+ char *backslash;
+ char *separator;
+
+ g_executable_dir[0] = '\0';
+ path[0] = '\0';
+
+#ifdef WIN32
+ {
+ DWORD result = GetModuleFileNameA(NULL, path, (DWORD)sizeof(path));
+ if (result > 0 && result < sizeof(path)) {
+ path[result] = '\0';
+ length = (size_t)result;
+ }
+ }
+#else
+#if defined(__linux__)
+ {
+ ssize_t result = readlink("/proc/self/exe", path, sizeof(path) - 1);
+ if (result > 0 && (size_t)result < sizeof(path)) {
+ path[result] = '\0';
+ length = (size_t)result;
+ }
+ }
+#endif
+ if (length == 0 && argv0 && argv0[0] &&
+ (strchr(argv0, '/') || strchr(argv0, '\\'))) {
+ char *resolved = realpath(argv0, path);
+ if (resolved)
+ length = strlen(path);
+ }
+#endif
+
+ if (length == 0)
+ return;
+
+ slash = strrchr(path, '/');
+ backslash = strrchr(path, '\\');
+ separator = slash;
+ if (backslash && (!separator || backslash > separator))
+ separator = backslash;
+
+ if (!separator)
+ return;
+
+ *separator = '\0';
+ if (path[0])
+ snprintf(g_executable_dir, sizeof(g_executable_dir), "%s", path);
+}
+
static const char *friidump_redump_dat_basename(disc_type type_id) {
switch (type_id) {
case DISC_TYPE_GAMECUBE:
redump_verify_result_init(&g_redump_result);
g_redump_attempted = false;
representation_note = (type_id == DISC_TYPE_XBOX)
- ? "XGD1 acquisition success and exact Redump hash identity are separate claims; documented synthetic reconstruction ranges may prevent an exact match."
+ ? "XGD1 acquisition success and exact Redump hash identity are separate claims; unresolved zero-filled pregame/postgame content may prevent an exact match."
: "";
if (options.no_redump_verify) {
return;
}
- dat_dir = (options.redump_dat_dir && options.redump_dat_dir[0]) ? options.redump_dat_dir : "redump_dat";
- snprintf(dat_path, sizeof(dat_path), "%s/%s", dat_dir, basename);
+ dat_dir = (options.redump_dat_dir && options.redump_dat_dir[0])
+ ? options.redump_dat_dir
+ : NULL;
+ redump_resolve_dat_path(dat_dir, g_executable_dir, basename,
+ dat_path, sizeof(dat_path));
if (output_size == 0)
output_size = friidump_file_size(output_path);
" --scan-dump-prefix <prefix> Optional raw 0xE7 window dump prefix for --hlds-e7-scan\n"
" --hlds-profile-report <file> Write selected HLDS profile/evidence JSON\n"
" --redump-dat-dir <dir> Directory containing canonical Redump DAT files\n"
- " (default: redump_dat)\n"
+ " (default: executable-relative redump_dat, then current directory)\n"
" --redump-report <file> Write atomic Redump evidence JSON\n"
" --no-redump-verify Disable automatic post-dump DAT verification\n"
+ " --xgd1-layout-probe <file> Read-only locked/unlocked XGD1 boundary probe;\n"
+ " writes atomic JSON and does not create an ISO\n"
+ " --xgd1-raw-id-probe <file> Modified-firmware cache-flushed, block-aligned raw-ID probe;\n"
+ " maps logical LBAs to decoded physical sector IDs\n"
" -A, --allmethods Try all known command/method combinations until\n"
" one works. Reopens the drive for each command so\n"
" command-specific vendor handlers are rebound.\n"
{"redump-dat-dir", 1, 0, 1006},
{"redump-report", 1, 0, 1007},
{"no-redump-verify", 0, 0, 1008},
+ {"xgd1-layout-probe", 1, 0, 1009},
+ {"xgd1-raw-id-probe", 1, 0, 1010},
#ifdef DEBUG
/* We don't want newbies to generate and put into circulation bad dumps, so this options are disabled for releases */
{"donottunscramble", 0, 0, 'n'},
options.redump_dat_dir = NULL;
options.redump_report = NULL;
options.no_redump_verify = false;
+ options.xgd1_layout_probe = false;
+ options.xgd1_layout_probe_report = NULL;
+ options.xgd1_raw_id_probe = false;
+ options.xgd1_raw_id_probe_report = NULL;
do {
#ifdef DEBUG
case 1008:
options.no_redump_verify = true;
break;
+ case 1009:
+ options.xgd1_layout_probe = true;
+ my_strdup (options.xgd1_layout_probe_report, optarg);
+ options.disctype = DISC_TYPE_XBOX;
+ break;
+ case 1010:
+ options.xgd1_raw_id_probe = true;
+ my_strdup (options.xgd1_raw_id_probe_report, optarg);
+ options.disctype = DISC_TYPE_XBOX;
+ break;
case -1:
break;
default:
fprintf (stderr, "WARNING: Extra parameters ignored\n");
}
+ if (options.xgd1_layout_probe || options.xgd1_raw_id_probe)
+ options.disctype = DISC_TYPE_XBOX;
+
/* Sanity checks... */
out = false;
if (!options.device && !options.raw_in) {
fprintf (stderr, "The -r, -i and -X options cannot be used together with -a.\n");
} else if (options.xiso_requested && (options.raw_out || options.iso_requested)) {
fprintf (stderr, "The -X/--xiso option is a separate Xbox output mode and cannot be combined with -r or -i.\n");
+ } else if ((options.xgd1_layout_probe || options.xgd1_raw_id_probe) &&
+ (options.autodump || options.raw_in || options.raw_out ||
+ options.iso_requested || options.xiso_requested ||
+ options.allmethods || options.hlds_e7_scan ||
+ options.hlds_e7_subcmd_sweep || options.hlds_e7_memrange_sweep ||
+ (options.xgd1_layout_probe && options.xgd1_raw_id_probe))) {
+ fprintf (stderr, "XGD1 probe modes are mutually exclusive read-only diagnostics and cannot be combined with dump, conversion, all-methods, or HLDS 0xE7 probe options.\n");
} else {
/* Specified options seem to make sense */
out = true;
u_int32_t current_sector = 0;
xbox_forced = (options.disctype == DISC_TYPE_XBOX);
- xbox_output_requested = xbox_forced || options.xiso_requested;
+ xbox_output_requested = xbox_forced || options.xiso_requested || options.xgd1_layout_probe || options.xgd1_raw_id_probe;
dump_attempted = false;
fprintf (stderr, "OK\n");
}
+ if (options.xgd1_layout_probe || options.xgd1_raw_id_probe) {
+#ifdef WIN32
+ int media_rc;
+ int media_sense_key;
+ int media_asc;
+ int media_ascq;
+ int probe_status;
+ bool stop_ok;
+ const char *probe_name;
+
+ probe_name = options.xgd1_raw_id_probe ? "XGD1 raw-sector ID" : "XGD1 logical-boundary";
+
+ if (!disc_is_xbox_challenge_drive (d)) {
+ fprintf (stderr,
+ "%s probe currently supports only the GDR-8050L challenge-handshake profile.\n",
+ probe_name);
+ return false;
+ }
+
+ if (options.xgd1_raw_id_probe &&
+ !(disc_get_hlds_e7_type (d) == 44 ||
+ disc_get_hlds_e7_type (d) == 45 ||
+ disc_get_hlds_e7_type (d) == 442 ||
+ disc_get_hlds_e7_type (d) == 443 ||
+ disc_get_hlds_e7_type (d) == 445)) {
+ fprintf (stderr,
+ "--xgd1-raw-id-probe requires the modified GDR-8050L HIT 0xE7 memdump profile.\n");
+ return false;
+ }
+
+ fprintf (stderr, "\nChecking for ready Xbox media before %s probing... ", probe_name);
+ media_rc = disc_media_preflight (d, 15000, &media_sense_key, &media_asc, &media_ascq);
+ if (media_rc <= 0) {
+ fprintf (stderr,
+ "Failed (sense %02X/%02X/%02X). Insert the disc, wait for spin-up, close AutoPlay/File Explorer, and retry.\n",
+ media_sense_key, media_asc, media_ascq);
+ return false;
+ }
+ fprintf (stderr, "OK\n");
+
+ gettimeofday (&(stats -> start_time), NULL);
+ if (options.xgd1_raw_id_probe)
+ probe_status = xbox_ref_xgd1_raw_id_probe_with_handle (
+ disc_get_native_handle (d), disc_get_device (d), options.xgd1_raw_id_probe_report);
+ else
+ probe_status = xbox_ref_xgd1_layout_probe_with_handle (
+ disc_get_native_handle (d), disc_get_device (d), options.xgd1_layout_probe_report);
+
+ fprintf (stderr, "Issuing STOP UNIT / spin-down after %s probe... ", probe_name);
+ stop_ok = disc_stop_unit (d, false);
+ fprintf (stderr, "%s\n", stop_ok ? "OK" : "Failed");
+ gettimeofday (&(stats -> end_time), NULL);
+ fprintf (stderr, "%s probe status: %s\n", probe_name, probe_status == 0 ? "OK" : "FAILED");
+ friidump_summary_reset();
+ return probe_status == 0;
+#else
+ fprintf (stderr, "XGD1 probe modes are available only in the Windows build.\n");
+ return false;
+#endif
+ }
+
if (options.hlds_e7_scan) {
out = disc_hlds_e7_scan (d, options.hlds_e7_scan_log, options.hlds_e7_scan_dump_prefix);
fprintf (stderr, "Issuing STOP UNIT / spin-down after HLDS 0xE7 scan... ");
/* First of all... */
drop_euid ();
+ friidump_init_executable_dir((argc > 0) ? argv[0] : NULL);
xbox_ref_log_open_for_target(NULL, 0);
welcome ();
my_free (options.raw_out);
my_free (options.raw_in);
my_free (options.hlds_profile_report);
+ my_free (options.xgd1_layout_probe_report);
+ my_free (options.xgd1_raw_id_probe_report);
}
if (xbox_ref_log_path())