+#define XGD1_LAYOUT_PROBE_SCHEMA_VERSION 1
+#define XGD1_LAYOUT_PROBE_SECTOR_BYTES 2048U
+#define XGD1_LAYOUT_PROBE_MAX_SAMPLES 20U
+
+typedef struct xbox_ref_probe_read_s
+{
+ int read_ok;
+ DWORD win32_error;
+ UCHAR scsi_status;
+ UCHAR sense_key;
+ UCHAR asc;
+ UCHAR ascq;
+ uint32_t nonzero_bytes;
+ int all_zero;
+ char sha1[41];
+ unsigned char data[XGD1_LAYOUT_PROBE_SECTOR_BYTES];
+} xbox_ref_probe_read;
+
+typedef struct xbox_ref_probe_sample_s
+{
+ uint32_t lba;
+ const char *label;
+ xbox_ref_probe_read read10;
+ xbox_ref_probe_read read12;
+} xbox_ref_probe_sample;
+
+typedef struct xbox_ref_probe_state_s
+{
+ const char *name;
+ uint32_t capacity;
+ int capacity_valid;
+ int state_verified;
+ uint32_t sample_count;
+ xbox_ref_probe_sample samples[XGD1_LAYOUT_PROBE_MAX_SAMPLES];
+} xbox_ref_probe_state;
+
+typedef struct xbox_ref_probe_point_s
+{
+ uint32_t lba;
+ const char *label;
+} xbox_ref_probe_point;
+
+typedef struct xbox_ref_sptd_with_sense_s
+{
+ SCSI_PASS_THROUGH_DIRECT sptd;
+ ULONG filler;
+ UCHAR sense[32];
+} xbox_ref_sptd_with_sense;
+
+static const xbox_ref_probe_point xbox_ref_locked_probe_points[] = {
+ {0U, "locked_logical_start"},
+ {31U, "locked_early_lba_31"},
+ {32U, "locked_early_lba_32"},
+ {XGD1_VIDEO_L0_SECTORS - 1U, "video_l0_last"},
+ {XGD1_VIDEO_L0_SECTORS, "locked_video_l1_first"},
+ {XGD1_VIDEO_TOTAL_SECTORS - 1U, "locked_video_last"},
+ {XGD1_VIDEO_TOTAL_SECTORS, "locked_capacity_plus_one"},
+ {XGD1_GAME_OUTPUT_START_LBA - 1U, "pregame_output_last"},
+ {XGD1_GAME_OUTPUT_START_LBA, "game_output_start"},
+ {XGD1_REDUMP_LAYER_BREAK_LBA - 1U, "output_layer_break_minus_one"},
+ {XGD1_REDUMP_LAYER_BREAK_LBA, "output_layer_break"},
+ {XGD1_VIDEO_L1_OUTPUT_START_LBA - 1U, "postgame_output_last"},
+ {XGD1_VIDEO_L1_OUTPUT_START_LBA, "video_l1_output_start"},
+ {XGD1_FULL_REDUMP_SECTORS - 1U, "full_output_last"}
+};
+
+static const xbox_ref_probe_point xbox_ref_unlocked_probe_points[] = {
+ {0U, "unlocked_source_start"},
+ {XGD1_XISO_LEADIN_SECTORS - 1U, "unlocked_source_leadin_last"},
+ {XGD1_GAME_SOURCE_START_LBA, "xdfs_source_start"},
+ {XGD1_GAME_SOURCE_START_LBA + 1U, "xdfs_source_next"},
+ {(XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) - 1U, "synthetic_gap_length_minus_one"},
+ {XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS, "synthetic_gap_length"},
+ {XGD1_GAME_OUTPUT_START_LBA - 1U, "pregame_output_last_as_unlocked_source"},
+ {XGD1_GAME_OUTPUT_START_LBA, "game_output_start_as_unlocked_source"},
+ {(XGD1_REDUMP_LAYER_BREAK_LBA - XGD1_GAME_OUTPUT_START_LBA) - 1U, "mapped_layer_break_source_minus_one"},
+ {XGD1_REDUMP_LAYER_BREAK_LBA - XGD1_GAME_OUTPUT_START_LBA, "mapped_layer_break_source"},
+ {XGD1_GAME_SOURCE_START_LBA + XGD1_GAME_SOURCE_SECTORS - 1U, "unlocked_source_last"},
+ {REDUMP_SECTORS, "unlocked_capacity_plus_one"},
+ {XGD1_GAME_OUTPUT_START_LBA + REDUMP_SECTORS, "postgame_output_start_as_unlocked_source"},
+ {XGD1_VIDEO_L1_OUTPUT_START_LBA, "video_l1_output_start_as_unlocked_source"}
+};
+
+static void xbox_ref_probe_parse_sense(const UCHAR *sense,
+ UCHAR *sense_key,
+ UCHAR *asc,
+ UCHAR *ascq)
+{
+ UCHAR response;
+
+ if (sense_key) *sense_key = 0;
+ if (asc) *asc = 0;
+ if (ascq) *ascq = 0;
+ if (!sense)
+ return;
+
+ response = (UCHAR)(sense[0] & 0x7f);
+ if (response == 0x70 || response == 0x71)
+ {
+ if (sense_key) *sense_key = (UCHAR)(sense[2] & 0x0f);
+ if (asc) *asc = sense[12];
+ if (ascq) *ascq = sense[13];
+ }
+ else if (response == 0x72 || response == 0x73)
+ {
+ if (sense_key) *sense_key = (UCHAR)(sense[1] & 0x0f);
+ if (asc) *asc = sense[2];
+ if (ascq) *ascq = sense[3];
+ }
+}
+
+static void xbox_ref_probe_sha1(const unsigned char *data,
+ uint32_t data_size,
+ char out_sha1[41])
+{
+ SHA1_CTX ctx;
+ unsigned char digest[20];
+ uint32_t i;
+
+ if (!out_sha1)
+ return;
+ out_sha1[0] = '\0';
+ if (!data || data_size == 0)
+ return;
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, data, data_size);
+ SHA1_Final(digest, &ctx);
+
+ for (i = 0; i < 20U; ++i)
+ sprintf(out_sha1 + (i * 2U), "%02x", digest[i]);
+ out_sha1[40] = '\0';
+}
+
+static void xbox_ref_probe_read_one(HANDLE hDevice,
+ UCHAR opcode,
+ uint32_t lba,
+ xbox_ref_probe_read *result)
+{
+ xbox_ref_sptd_with_sense packet;
+ unsigned char *buffer;
+ DWORD bytes_returned;
+ BOOL ioctl_ok;
+ uint32_t i;
+
+ if (!result)
+ return;
+ memset(result, 0, sizeof(*result));
+
+ buffer = (unsigned char *)VirtualAlloc(NULL,
+ XGD1_LAYOUT_PROBE_SECTOR_BYTES,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE);
+ if (!buffer)
+ {
+ result->win32_error = ERROR_NOT_ENOUGH_MEMORY;
+ return;
+ }
+
+ memset(buffer, 0, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
+ memset(&packet, 0, sizeof(packet));
+
+ packet.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
+ packet.sptd.CdbLength = (opcode == 0xA8) ? 12 : 10;
+ packet.sptd.SenseInfoLength = sizeof(packet.sense);
+ packet.sptd.DataIn = SCSI_IOCTL_DATA_IN;
+ packet.sptd.DataTransferLength = XGD1_LAYOUT_PROBE_SECTOR_BYTES;
+ packet.sptd.TimeOutValue = 10;
+ packet.sptd.DataBuffer = buffer;
+ packet.sptd.SenseInfoOffset = offsetof(xbox_ref_sptd_with_sense, sense);
+ packet.sptd.Cdb[0] = opcode;
+ packet.sptd.Cdb[2] = (UCHAR)((lba >> 24) & 0xff);
+ packet.sptd.Cdb[3] = (UCHAR)((lba >> 16) & 0xff);
+ packet.sptd.Cdb[4] = (UCHAR)((lba >> 8) & 0xff);
+ packet.sptd.Cdb[5] = (UCHAR)(lba & 0xff);
+
+ if (opcode == 0xA8)
+ {
+ packet.sptd.Cdb[9] = 1;
+ }
+ else
+ {
+ packet.sptd.Cdb[8] = 1;
+ }
+
+ bytes_returned = 0;
+ ioctl_ok = DeviceIoControl(hDevice,
+ IOCTL_SCSI_PASS_THROUGH_DIRECT,
+ &packet,
+ sizeof(packet),
+ &packet,
+ sizeof(packet),
+ &bytes_returned,
+ NULL);
+
+ result->win32_error = ioctl_ok ? ERROR_SUCCESS : GetLastError();
+ result->scsi_status = packet.sptd.ScsiStatus;
+ xbox_ref_probe_parse_sense(packet.sense,
+ &result->sense_key,
+ &result->asc,
+ &result->ascq);
+ result->read_ok = (ioctl_ok && packet.sptd.ScsiStatus == 0) ? 1 : 0;
+
+ if (result->read_ok)
+ {
+ memcpy(result->data, buffer, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
+ result->nonzero_bytes = 0;
+ for (i = 0; i < XGD1_LAYOUT_PROBE_SECTOR_BYTES; ++i)
+ {
+ if (buffer[i] != 0)
+ result->nonzero_bytes++;
+ }
+ result->all_zero = (result->nonzero_bytes == 0U) ? 1 : 0;
+ xbox_ref_probe_sha1(buffer,
+ XGD1_LAYOUT_PROBE_SECTOR_BYTES,
+ result->sha1);
+ }
+
+ VirtualFree(buffer, 0, MEM_RELEASE);
+}
+
+static void xbox_ref_probe_capture_state(HANDLE hDevice,
+ xbox_ref_probe_state *state,
+ const xbox_ref_probe_point *points,
+ uint32_t point_count)
+{
+ uint32_t i;
+
+ if (!state || !points)
+ return;
+
+ if (point_count > XGD1_LAYOUT_PROBE_MAX_SAMPLES)
+ point_count = XGD1_LAYOUT_PROBE_MAX_SAMPLES;
+
+ state->sample_count = point_count;
+ for (i = 0; i < point_count; ++i)
+ {
+ state->samples[i].lba = points[i].lba;
+ state->samples[i].label = points[i].label;
+
+ printf("[XGD1-PROBE] %s: probing LBA %u (%s) with READ(10) and READ(12).\n",
+ state->name ? state->name : "state",
+ points[i].lba,
+ points[i].label ? points[i].label : "unlabeled");
+
+ xbox_ref_probe_read_one(hDevice,
+ 0x28,
+ points[i].lba,
+ &state->samples[i].read10);
+ xbox_ref_probe_read_one(hDevice,
+ 0xA8,
+ points[i].lba,
+ &state->samples[i].read12);
+ }
+}
+
+static void xbox_ref_probe_json_string(FILE *json, const char *value)
+{
+ const unsigned char *p;
+
+ if (!json)
+ return;
+ if (!value)
+ value = "";
+
+ fputc('"', json);
+ p = (const unsigned char *)value;
+ while (*p)
+ {
+ switch (*p)
+ {
+ case '\\': fputs("\\\\", json); break;
+ case '"': fputs("\\\"", json); break;
+ case '\b': fputs("\\b", json); break;
+ case '\f': fputs("\\f", json); break;
+ case '\n': fputs("\\n", json); break;
+ case '\r': fputs("\\r", json); break;
+ case '\t': fputs("\\t", json); break;
+ default:
+ if (*p < 0x20)
+ fprintf(json, "\\u%04x", (unsigned int)*p);
+ else
+ fputc(*p, json);
+ break;
+ }
+ ++p;
+ }
+ fputc('"', json);
+}
+
+static void xbox_ref_probe_json_hex(FILE *json,
+ const unsigned char *data,
+ uint32_t data_size)
+{
+ uint32_t i;
+
+ if (!json)
+ return;
+ fputc('"', json);
+ if (data)
+ {
+ for (i = 0; i < data_size; ++i)
+ fprintf(json, "%02x", data[i]);
+ }
+ fputc('"', json);
+}
+
+static void xbox_ref_probe_write_cdb(FILE *json,
+ UCHAR opcode,
+ uint32_t lba)
+{
+ if (!json)
+ return;
+
+ if (opcode == 0xA8)
+ {
+ fprintf(json,
+ "\"a800%08x000000010000\"",
+ lba);
+ }
+ else
+ {
+ fprintf(json,
+ "\"2800%08x00000100\"",
+ lba);
+ }
+}
+
+static void xbox_ref_probe_write_read(FILE *json,
+ const char *indent,
+ const char *name,
+ const xbox_ref_probe_read *read)
+{
+ if (!json || !read)
+ return;
+
+ fprintf(json, "%s", indent);
+ xbox_ref_probe_json_string(json, name);
+ fprintf(json, ": {\n");
+ fprintf(json, "%s \"read_ok\": %s,\n", indent, read->read_ok ? "true" : "false");
+ fprintf(json, "%s \"win32_error\": %lu,\n", indent, (unsigned long)read->win32_error);
+ fprintf(json, "%s \"scsi_status\": %u,\n", indent, (unsigned int)read->scsi_status);
+ fprintf(json, "%s \"sense_key\": %u,\n", indent, (unsigned int)read->sense_key);
+ fprintf(json, "%s \"asc\": %u,\n", indent, (unsigned int)read->asc);
+ fprintf(json, "%s \"ascq\": %u,\n", indent, (unsigned int)read->ascq);
+ if (read->read_ok)
+ {
+ fprintf(json, "%s \"nonzero_bytes\": %u,\n", indent, read->nonzero_bytes);
+ fprintf(json, "%s \"all_zero\": %s,\n", indent, read->all_zero ? "true" : "false");
+ }
+ else
+ {
+ fprintf(json, "%s \"nonzero_bytes\": null,\n", indent);
+ fprintf(json, "%s \"all_zero\": null,\n", indent);
+ }
+ fprintf(json, "%s \"sha1\": ", indent);
+ if (read->read_ok)
+ xbox_ref_probe_json_string(json, read->sha1);
+ else
+ fprintf(json, "null");
+ fprintf(json, ",\n");
+ fprintf(json, "%s \"data_hex\": ", indent);
+ if (read->read_ok)
+ xbox_ref_probe_json_hex(json, read->data, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
+ else
+ xbox_ref_probe_json_string(json, "");
+ fprintf(json, "\n%s}", indent);
+}
+
+static void xbox_ref_probe_write_state(FILE *json,
+ const xbox_ref_probe_state *state,
+ int trailing_comma)
+{
+ uint32_t i;
+
+ fprintf(json, " {\n");
+ fprintf(json, " \"name\": ");
+ xbox_ref_probe_json_string(json, state->name);
+ fprintf(json, ",\n");
+ fprintf(json, " \"capacity_valid\": %s,\n", state->capacity_valid ? "true" : "false");
+ fprintf(json, " \"capacity_sectors\": %u,\n", state->capacity);
+ fprintf(json, " \"state_verified\": %s,\n", state->state_verified ? "true" : "false");
+ fprintf(json, " \"samples\": [\n");
+
+ for (i = 0; i < state->sample_count; ++i)
+ {
+ const xbox_ref_probe_sample *sample = &state->samples[i];
+ int identical = 0;
+
+ if (sample->read10.read_ok && sample->read12.read_ok)
+ {
+ identical = (memcmp(sample->read10.data,
+ sample->read12.data,
+ XGD1_LAYOUT_PROBE_SECTOR_BYTES) == 0) ? 1 : 0;
+ }
+
+ fprintf(json, " {\n");
+ fprintf(json, " \"lba\": %u,\n", sample->lba);
+ fprintf(json, " \"label\": ");
+ xbox_ref_probe_json_string(json, sample->label);
+ fprintf(json, ",\n");
+ fprintf(json, " \"read10_cdb_hex\": ");
+ xbox_ref_probe_write_cdb(json, 0x28, sample->lba);
+ fprintf(json, ",\n");
+ fprintf(json, " \"read12_cdb_hex\": ");
+ xbox_ref_probe_write_cdb(json, 0xA8, sample->lba);
+ fprintf(json, ",\n");
+ xbox_ref_probe_write_read(json, " ", "read10", &sample->read10);
+ fprintf(json, ",\n");
+ xbox_ref_probe_write_read(json, " ", "read12", &sample->read12);
+ fprintf(json, ",\n");
+ fprintf(json,
+ " \"read10_read12_comparable\": %s,\n",
+ (sample->read10.read_ok && sample->read12.read_ok) ? "true" : "false");
+ fprintf(json, " \"read10_read12_identical\": ");
+ if (sample->read10.read_ok && sample->read12.read_ok)
+ fprintf(json, "%s\n", identical ? "true" : "false");
+ else
+ fprintf(json, "null\n");
+ fprintf(json, " }%s\n", (i + 1U < state->sample_count) ? "," : "");
+ }
+
+ fprintf(json, " ]\n");
+ fprintf(json, " }%s\n", trailing_comma ? "," : "");
+}
+
+static BOOL xbox_ref_probe_write_report(const char *report_path,
+ const char *device,
+ uint32_t entry_capacity,
+ int entry_game_view,
+ int volume_lock_acquired,
+ const xbox_ref_probe_state *locked_state,
+ const xbox_ref_probe_state *unlocked_state,
+ int restore_attempted,
+ uint32_t restored_capacity,
+ int restore_verified)
+{
+ char tmp_path[XBOX_REF_RESULT_PATH_MAX];
+ const char *final_path;
+ FILE *json;
+ int fd;
+ BOOL moved;
+
+ final_path = (report_path && report_path[0]) ? report_path : "xgd1_layout_probe.json";
+ {
+ int path_length = snprintf(tmp_path,
+ sizeof(tmp_path),
+ "%s.tmp.%lu",
+ final_path,
+ (unsigned long)GetCurrentProcessId());
+ if (path_length < 0 || (size_t)path_length >= sizeof(tmp_path))
+ {
+ printf("[XGD1-PROBE] Fatal: report path is too long.\n");
+ return FALSE;
+ }
+ }
+
+ json = fopen(tmp_path, "wb");
+ if (!json)
+ {
+ printf("[XGD1-PROBE] Fatal: could not create temporary report %s.\n", tmp_path);
+ return FALSE;
+ }
+
+ fprintf(json, "{\n");
+ fprintf(json, " \"schema_version\": %d,\n", XGD1_LAYOUT_PROBE_SCHEMA_VERSION);
+ fprintf(json, " \"producer\": \"friidump-0.5.3.11\",\n");
+ fprintf(json, " \"probe\": \"original_xbox_xgd1_logical_layout_boundary\",\n");
+ fprintf(json, " \"device\": ");
+ xbox_ref_probe_json_string(json, device ? device : "");
+ fprintf(json, ",\n");
+ fprintf(json, " \"safety\": {\n");
+ fprintf(json, " \"read_only_sector_commands\": true,\n");
+ fprintf(json, " \"authentication_handshake_used\": true,\n");
+ fprintf(json, " \"tray_cycle_used\": true,\n");
+ fprintf(json, " \"firmware_write_used\": false,\n");
+ fprintf(json, " \"flash_command_used\": false\n");
+ fprintf(json, " },\n");
+ fprintf(json, " \"constants\": {\n");
+ fprintf(json, " \"full_output_sectors\": %u,\n", XGD1_FULL_REDUMP_SECTORS);
+ fprintf(json, " \"game_output_start_lba\": %u,\n", XGD1_GAME_OUTPUT_START_LBA);
+ fprintf(json, " \"game_view_sectors\": %u,\n", REDUMP_SECTORS);
+ fprintf(json, " \"video_total_sectors\": %u,\n", XGD1_VIDEO_TOTAL_SECTORS);
+ fprintf(json, " \"video_l0_sectors\": %u,\n", XGD1_VIDEO_L0_SECTORS);
+ fprintf(json, " \"video_l1_sectors\": %u,\n", XGD1_VIDEO_L1_SECTORS);
+ fprintf(json, " \"video_l1_output_start_lba\": %u,\n", XGD1_VIDEO_L1_OUTPUT_START_LBA);
+ fprintf(json, " \"output_layer_break_lba\": %u\n", XGD1_REDUMP_LAYER_BREAK_LBA);
+ fprintf(json, " },\n");
+ fprintf(json, " \"entry\": {\n");
+ fprintf(json, " \"capacity_sectors\": %u,\n", entry_capacity);
+ fprintf(json, " \"game_view\": %s,\n", entry_game_view ? "true" : "false");
+ fprintf(json, " \"classification\": ");
+ if (xbox_ref_capacity_is_xgd1_game_view(entry_capacity))
+ xbox_ref_probe_json_string(json, "unlocked_game");
+ else if (xbox_ref_capacity_is_xgd1_locked_view(entry_capacity))
+ xbox_ref_probe_json_string(json, "locked_video");
+ else
+ xbox_ref_probe_json_string(json, "other_or_unknown");
+ fprintf(json, "\n");
+ fprintf(json, " },\n");
+ fprintf(json, " \"volume_lock_acquired_at_least_once\": %s,\n", volume_lock_acquired ? "true" : "false");
+ fprintf(json,
+ " \"required_states_verified\": %s,\n",
+ (locked_state->state_verified && unlocked_state->state_verified) ? "true" : "false");
+ fprintf(json, " \"states\": [\n");
+ xbox_ref_probe_write_state(json, locked_state, 1);
+ xbox_ref_probe_write_state(json, unlocked_state, 0);
+ fprintf(json, " ],\n");
+ fprintf(json, " \"restoration\": {\n");
+ fprintf(json, " \"attempted\": %s,\n", restore_attempted ? "true" : "false");
+ fprintf(json, " \"capacity_sectors\": %u,\n", restored_capacity);
+ fprintf(json, " \"verified\": %s\n", restore_verified ? "true" : "false");
+ fprintf(json, " },\n");
+ fprintf(json, " \"interpretation_boundary\": {\n");
+ fprintf(json, " \"pregame_padding_resolved\": false,\n");
+ fprintf(json, " \"postgame_padding_resolved\": false,\n");
+ fprintf(json, " \"game_leadin_resolved\": false,\n");
+ fprintf(json, " \"note\": \"This report records ordinary logical READ(10)/READ(12) behavior in locked/video and unlocked/game states. It does not claim that inaccessible physical filler sectors are zero or that the current reconstructed image is Redump-exact.\"\n");
+ fprintf(json, " }\n");
+ fprintf(json, "}\n");
+
+ if (fflush(json) != 0)
+ {
+ fclose(json);
+ DeleteFileA(tmp_path);
+ return FALSE;
+ }
+
+ fd = _fileno(json);
+ if (fd < 0 || _commit(fd) != 0)
+ {
+ fclose(json);
+ DeleteFileA(tmp_path);
+ return FALSE;
+ }
+
+ if (fclose(json) != 0)
+ {
+ DeleteFileA(tmp_path);
+ return FALSE;
+ }
+
+ moved = MoveFileExA(tmp_path,
+ final_path,
+ MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
+ if (!moved)
+ {
+ printf("[XGD1-PROBE] Fatal: could not atomically publish report %s (error %lu).\n",
+ final_path,
+ (unsigned long)GetLastError());
+ DeleteFileA(tmp_path);
+ return FALSE;
+ }
+
+ printf("[XGD1-PROBE] Atomic report written: %s\n", final_path);
+ return TRUE;
+}
+
+static int xbox_ref_xgd1_layout_probe_core(HANDLE hDevice,
+ const char *device,
+ const char *report_path,
+ BOOL owns_handle)
+{
+ xbox_ref_probe_state locked_state;
+ xbox_ref_probe_state unlocked_state;
+ uint32_t entry_capacity;
+ uint32_t restored_capacity;
+ int entry_game_view;
+ int volume_lock_acquired;
+ int volume_lock_ever;
+ int restore_attempted;
+ int restore_verified;
+ int states_verified;
+ DWORD bytes_returned;
+ BOOL report_ok;
+
+ memset(&locked_state, 0, sizeof(locked_state));
+ memset(&unlocked_state, 0, sizeof(unlocked_state));
+ locked_state.name = "locked_video";
+ unlocked_state.name = "unlocked_game";
+ entry_capacity = 0;
+ restored_capacity = 0;
+ entry_game_view = 0;
+ volume_lock_acquired = 0;
+ volume_lock_ever = 0;
+ restore_attempted = 0;
+ restore_verified = 0;
+ states_verified = 0;
+ bytes_returned = 0;
+
+ xbox_ref_log_open_for_target(report_path, xbox_ref_drive_letter_from_device(device));
+ printf("[XGD1-PROBE] Starting read-only logical layout boundary probe.\n");
+ printf("[XGD1-PROBE] The existing XGD1 output layout will not be modified.\n");
+
+ if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
+ {
+ printf("[XGD1-PROBE] Fatal: invalid drive handle.\n");
+ if (owns_handle)
+ xbox_ref_log_close();
+ return 1;
+ }
+
+ if (!EnsureDriveReady(hDevice, 30000))
+ {
+ printf("[XGD1-PROBE] Fatal: media did not become ready.\n");
+ if (owns_handle)
+ xbox_ref_log_close();
+ return 1;
+ }
+
+ entry_capacity = GetTotalSectors(hDevice);
+ entry_game_view = xbox_ref_capacity_is_xgd1_game_view(entry_capacity) ? 1 : 0;
+ printf("[XGD1-PROBE] Entry READ CAPACITY: %u sectors (%s).\n",
+ entry_capacity,
+ entry_game_view ? "game view" : "locked/video or unknown view");
+
+ DeviceIoControl(hDevice,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytes_returned,
+ NULL);
+
+ printf("[XGD1-PROBE] Cycling tray to establish locked/video view.\n");
+ AutomateTrayCycle(hDevice);
+ locked_state.capacity = xbox_ref_refresh_ready_capacity(hDevice);
+ locked_state.capacity_valid = locked_state.capacity != 0U;
+ locked_state.state_verified = (locked_state.capacity_valid &&
+ xbox_ref_capacity_is_xgd1_locked_view(locked_state.capacity)) ? 1 : 0;
+ printf("[XGD1-PROBE] Locked/video READ CAPACITY: %u sectors; verified=%s.\n",
+ locked_state.capacity,
+ locked_state.state_verified ? "yes" : "no");
+
+ if (DeviceIoControl(hDevice,
+ FSCTL_LOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytes_returned,
+ NULL))
+ {
+ volume_lock_acquired = 1;
+ volume_lock_ever = 1;
+ printf("[XGD1-PROBE] Windows volume lock acquired.\n");
+ }
+ else
+ {
+ printf("[XGD1-PROBE][WARN] Windows volume lock was not acquired; close AutoPlay and Explorer dialogs if results are unstable.\n");
+ }
+
+ SetDriveSpeedMax(hDevice);
+ xbox_ref_probe_capture_state(hDevice,
+ &locked_state,
+ xbox_ref_locked_probe_points,
+ (uint32_t)(sizeof(xbox_ref_locked_probe_points) /
+ sizeof(xbox_ref_locked_probe_points[0])));
+
+ printf("[XGD1-PROBE] Applying the full Xbox handshake to establish game view.\n");
+ UnlockDrive(hDevice);
+ unlocked_state.capacity = xbox_ref_refresh_ready_capacity(hDevice);
+ unlocked_state.capacity_valid = unlocked_state.capacity != 0U;
+ unlocked_state.state_verified = (unlocked_state.capacity_valid &&
+ xbox_ref_capacity_is_xgd1_game_view(unlocked_state.capacity)) ? 1 : 0;
+ printf("[XGD1-PROBE] Unlocked/game READ CAPACITY: %u sectors; verified=%s.\n",
+ unlocked_state.capacity,
+ unlocked_state.state_verified ? "yes" : "no");
+
+ xbox_ref_probe_capture_state(hDevice,
+ &unlocked_state,
+ xbox_ref_unlocked_probe_points,
+ (uint32_t)(sizeof(xbox_ref_unlocked_probe_points) /
+ sizeof(xbox_ref_unlocked_probe_points[0])));
+
+ if (volume_lock_acquired)
+ {
+ DeviceIoControl(hDevice,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytes_returned,
+ NULL);
+ volume_lock_acquired = 0;
+ }
+
+ if (!entry_game_view && entry_capacity != 0U)
+ {
+ restore_attempted = 1;
+ printf("[XGD1-PROBE] Restoring the entry locked/video state with a final tray cycle.\n");
+ AutomateTrayCycle(hDevice);
+ restored_capacity = xbox_ref_refresh_ready_capacity(hDevice);
+ restore_verified = (restored_capacity != 0U &&
+ xbox_ref_capacity_is_xgd1_locked_view(restored_capacity)) ? 1 : 0;
+ }
+ else
+ {
+ restored_capacity = GetTotalSectors(hDevice);
+ restore_verified = (entry_game_view &&
+ xbox_ref_capacity_is_xgd1_game_view(restored_capacity)) ? 1 : 0;
+ }
+
+ states_verified = (locked_state.state_verified &&
+ unlocked_state.state_verified) ? 1 : 0;
+
+ report_ok = xbox_ref_probe_write_report(report_path,
+ device,
+ entry_capacity,
+ entry_game_view,
+ volume_lock_ever,
+ &locked_state,
+ &unlocked_state,
+ restore_attempted,
+ restored_capacity,
+ restore_verified);
+
+ if (owns_handle)
+ {
+ printf("[XGD1-PROBE] Issuing STOP UNIT / spin-down after probe... ");
+ printf("%s\n", StopDriveUnit(hDevice) ? "OK" : "FAILED");
+ CloseDrive(hDevice);
+ xbox_ref_log_close();
+ }
+
+ if (!report_ok)
+ return 1;
+ if (!states_verified)
+ {
+ printf("[XGD1-PROBE] Probe report is partial because one or more drive states were not verified.\n");
+ return 1;
+ }
+
+ printf("[XGD1-PROBE] Probe complete. Synthetic ranges remain unresolved until the captured evidence supports a source mapping.\n");
+ return 0;
+}
+
+