temporarily turn off symbol server stuff - switch off spoof for step-over

This commit is contained in:
Ryan Fleury
2026-06-09 09:27:23 -07:00
parent 132751777f
commit 9955c8c1a7
16 changed files with 159 additions and 76 deletions
+2 -2
View File
@@ -5,7 +5,7 @@ target:
{ {
executable: "build/raddbg.exe" executable: "build/raddbg.exe"
working_directory: "../raddebugger" working_directory: "../raddebugger"
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user --project:C:/devel/raddebugger/build/raddbg_test.project" arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user --project:C:/devel/raddebugger/build/raddbg_test.project --capture"
debug_subprocesses: 0 debug_subprocesses: 0
enabled: 1 enabled: 1
} }
@@ -57,5 +57,5 @@ target:
{ {
executable: "build/raddbg.exe" executable: "build/raddbg.exe"
working_directory: build working_directory: build
arguments: "--bin --rdi --thread_count=1 C:/SymbolCache/kernelbase.pdb/53B51385668728BA4297C9C78EEC92DD1/kernelbase.pdb" arguments: "--bin --rdi --thread_count=1 C:/SymbolCache/kernel32.pdb/E02F64ED8DA50EC6E7691C0AC0BC25781/kernel32.pdb"
} }
+4 -3
View File
@@ -270,9 +270,10 @@ enum
{ {
D_TrapFlag_IgnoreStackPointerCheck = (1<<0), D_TrapFlag_IgnoreStackPointerCheck = (1<<0),
D_TrapFlag_SingleStepAfterHit = (1<<1), D_TrapFlag_SingleStepAfterHit = (1<<1),
D_TrapFlag_SaveStackPointer = (1<<2), D_TrapFlag_SaveStackPointerBefore = (1<<2),
D_TrapFlag_BeginSpoofMode = (1<<3), D_TrapFlag_SaveStackPointerAfter = (1<<3),
D_TrapFlag_EndStepping = (1<<4), D_TrapFlag_BeginSpoofMode = (1<<4),
D_TrapFlag_EndStepping = (1<<5),
}; };
typedef struct D_Trap D_Trap; typedef struct D_Trap D_Trap;
+40 -31
View File
@@ -2666,10 +2666,12 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
////////////////////////////// //////////////////////////////
//- rjf: no found debug info path -> try to fall back on symbol server cache path //- rjf: no found debug info path -> try to fall back on symbol server cache path
// //
#if 0
if(initial_debug_info_path.size == 0) if(initial_debug_info_path.size == 0)
{ {
initial_debug_info_path = smsv_local_path_from_key(arena, str8_skip_last_slash(module_info->debug_info_path), module_info->debug_info_guid, module_info->debug_info_age); initial_debug_info_path = smsv_local_path_from_key(arena, str8_skip_last_slash(module_info->debug_info_path), module_info->debug_info_guid, module_info->debug_info_age);
} }
#endif
////////////////////////////// //////////////////////////////
//- rjf: write 1 at attachment marker, to signify attachment //- rjf: write 1 at attachment marker, to signify attachment
@@ -3086,10 +3088,8 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
{ {
d_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); d_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value);
} }
}
}
//- rjf: irrespective of what event came back, we should ALWAYS check the // rjf: irrespective of what event came back, we should ALWAYS check the
// spoof's thread and see if it hit the spoof address, because we may have // spoof's thread and see if it hit the spoof address, because we may have
// simply been sent other debug events first // simply been sent other debug events first
if(spoof != 0) if(spoof != 0)
@@ -3107,6 +3107,8 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
d_thread_write_reg_block(spoof->thread, regs_block); d_thread_write_reg_block(spoof->thread, regs_block);
} }
} }
}
}
//- rjf: push ctrl events associated with this demon event //- rjf: push ctrl events associated with this demon event
D_EventList evts = {0}; D_EventList evts = {0};
@@ -5154,22 +5156,38 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
} }
} }
//- rjf: trap net on on-target threads trigger trap net logic //- rjf: trap net logic: stack pointer check on target thread
B32 use_trap_net_logic = 0; B32 stack_pointer_check_passes = 0;
if(!hard_stop && use_stepping_logic && hit_trap_net_bp) if(!hard_stop && use_stepping_logic && hit_trap_net_bp && dmn_handle_match(event->thread, d_dmn_from_handle(target_thread)))
{ {
if(dmn_handle_match(event->thread, d_dmn_from_handle(target_thread))) U64 sp = d_sp_from_thread(target_thread);
stack_pointer_check_passes = ((hit_trap_flags & D_TrapFlag_IgnoreStackPointerCheck) || (sp == sp_check_value));
}
//- rjf: trap net on on-target threads trigger trap net logic, *if* the stack pointer check passes.
// if it doesn't -> step over trap net & continue
B32 use_trap_net_logic = 0;
if(!hard_stop && use_stepping_logic && hit_trap_net_bp && dmn_handle_match(event->thread, d_dmn_from_handle(target_thread)))
{
if(stack_pointer_check_passes)
{ {
use_trap_net_logic = 1; use_trap_net_logic = 1;
} }
else
{
step_past_trap_net = 1;
use_stepping_logic = 0;
}
} }
//- rjf: trap net logic: stack pointer check //- rjf: trap net logic: save stack pointer *before* step-over
B32 stack_pointer_matches = 0; if(!hard_stop && use_trap_net_logic)
if(use_trap_net_logic)
{ {
U64 sp = d_sp_from_thread(target_thread); if(hit_trap_flags & D_TrapFlag_SaveStackPointerBefore)
stack_pointer_matches = (sp == sp_check_value); {
sp_check_value = d_sp_from_thread(target_thread);
log_infof("sp_check_value = 0x%I64x\n", sp_check_value);
}
} }
//- rjf: trap net logic: single step after hit //- rjf: trap net logic: single step after hit
@@ -5217,6 +5235,16 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
} }
} }
//- rjf: trap net logic: save stack pointer *after* step-over
if(!hard_stop && use_trap_net_logic)
{
if(hit_trap_flags & D_TrapFlag_SaveStackPointerAfter)
{
sp_check_value = d_sp_from_thread(target_thread);
log_infof("sp_check_value = 0x%I64x\n", sp_check_value);
}
}
//- rjf: trap net logic: begin spoof mode //- rjf: trap net logic: begin spoof mode
B32 begin_spoof_mode = 0; B32 begin_spoof_mode = 0;
if(!hard_stop && use_trap_net_logic) if(!hard_stop && use_trap_net_logic)
@@ -5234,35 +5262,16 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
} }
} }
//- rjf: trap net logic: save stack pointer
B32 save_stack_pointer = 0;
if(!hard_stop && use_trap_net_logic)
{
if(hit_trap_flags & D_TrapFlag_SaveStackPointer)
{
if(stack_pointer_matches) LogInfoNamedBlockF("trap_net__save_sp")
{
save_stack_pointer = 1;
sp_check_value = d_sp_from_thread(target_thread);
log_infof("sp_check_value = 0x%I64x\n", sp_check_value);
}
}
}
//- rjf: trap net logic: end stepping //- rjf: trap net logic: end stepping
B32 trap_net_stop = 0; B32 trap_net_stop = 0;
if(!hard_stop && use_trap_net_logic) if(!hard_stop && use_trap_net_logic)
{ {
if(hit_trap_flags & D_TrapFlag_EndStepping) LogInfoNamedBlockF("trap_net__end_step") if(hit_trap_flags & D_TrapFlag_EndStepping) LogInfoNamedBlockF("trap_net__end_step")
{
if((hit_trap_flags & D_TrapFlag_IgnoreStackPointerCheck) ||
stack_pointer_matches)
{ {
trap_net_stop = 1; trap_net_stop = 1;
use_trap_net_logic = 0; use_trap_net_logic = 0;
} }
} }
}
//} //}
// //
+11 -3
View File
@@ -516,16 +516,24 @@ d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread)
} }
// rjf: call => save stack pointer before, single-step to go into call; trap on return
else if(point->inst_flags & DASM_InstFlag_Call)
{
flags |= (D_TrapFlag_SaveStackPointerBefore|D_TrapFlag_SingleStepAfterHit);
}
#if 0 // TODO(rjf): @spoof_stepping
// rjf: call => place spoof at return spot in stack, single-step after hitting // rjf: call => place spoof at return spot in stack, single-step after hitting
else if(point->inst_flags & DASM_InstFlag_Call) else if(point->inst_flags & DASM_InstFlag_Call)
{ {
flags |= (D_TrapFlag_BeginSpoofMode|D_TrapFlag_SingleStepAfterHit); flags |= (D_TrapFlag_BeginSpoofMode|D_TrapFlag_SingleStepAfterHit);
} }
#endif
// rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping // rjf: instruction changes stack pointer => single-step over, save off the stack pointer, keep stepping
else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer) else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer)
{ {
flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointer); flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointerAfter);
} }
// rjf: add if appropriate // rjf: add if appropriate
@@ -734,7 +742,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread)
// rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping // rjf: instruction changes stack pointer => save off the stack pointer, single-step over, keep stepping
else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer) else if(point->inst_flags & DASM_InstFlag_ChangesStackPointer)
{ {
flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointer); flags |= (D_TrapFlag_SingleStepAfterHit|D_TrapFlag_SaveStackPointerAfter);
} }
// rjf: add if appropriate // rjf: add if appropriate
+1
View File
@@ -682,6 +682,7 @@ di_async_tick(void)
//- rjf: kick off symbol server download, or check to see if we are actively downloading O.G. //- rjf: kick off symbol server download, or check to see if we are actively downloading O.G.
B32 og_is_downloading = 0; B32 og_is_downloading = 0;
if(og_path.size != 0)
{ {
B32 file_is_present = (properties_from_file_path(og_path).modified != 0); B32 file_is_present = (properties_from_file_path(og_path).modified != 0);
if(!file_is_present) if(!file_is_present)
+2
View File
@@ -146,6 +146,8 @@ typedef struct HTTP_Response HTTP_Response;
struct HTTP_Response struct HTTP_Response
{ {
U64 id; U64 id;
U64 off;
U64 off_opl;
B32 has_more; B32 has_more;
HTTP_StatusCode code; HTTP_StatusCode code;
String8 body; String8 body;
+1
View File
@@ -396,6 +396,7 @@ typedef RDI_U8 RDI_SymbolFlags;
typedef enum RDI_SymbolFlagsEnum typedef enum RDI_SymbolFlagsEnum
{ {
RDI_SymbolFlag_IsParam = 0x1, RDI_SymbolFlag_IsParam = 0x1,
RDI_SymbolFlag_IsThunk = 0x2,
} RDI_SymbolFlagsEnum; } RDI_SymbolFlagsEnum;
typedef RDI_U8 RDI_LocationKind; typedef RDI_U8 RDI_LocationKind;
+1
View File
@@ -849,6 +849,7 @@ typedef struct RDIM_Symbol RDIM_Symbol;
struct RDIM_Symbol struct RDIM_Symbol
{ {
struct RDIM_SymbolChunkNode *chunk; struct RDIM_SymbolChunkNode *chunk;
RDI_S32 is_thunk;
RDI_S32 is_extern; RDI_S32 is_extern;
RDI_S32 is_param; RDI_S32 is_param;
RDIM_String8 name; RDIM_String8 name;
+4 -8
View File
@@ -6634,18 +6634,14 @@ rd_window_frame(void)
UI_PermissionFlag_All) UI_PermissionFlag_All)
{ {
B32 has_footer = (is_lister && !is_anchored); B32 has_footer = (is_lister && !is_anchored);
F32 container_corner_top_radius_px = is_lister ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f; F32 container_corner_radius_px = has_footer ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f;
F32 container_corner_bottom_radius_px = has_footer ? ui_top_font_size()*1.f : ui_top_font_size()*0.15f;
// rjf: build top-level container box // rjf: build top-level container box
UI_Box *container = &ui_nil_box; UI_Box *container = &ui_nil_box;
UI_Rect(rect) UI_ChildLayoutAxis(Axis2_Y) UI_Rect(rect) UI_ChildLayoutAxis(Axis2_Y)
UI_Squish(0.1f-0.1f*open_t) UI_Squish(0.1f-0.1f*open_t)
UI_Transparency(1.f-open_t) UI_Transparency(1.f-open_t)
UI_CornerRadius00(container_corner_top_radius_px) UI_CornerRadius(container_corner_radius_px)
UI_CornerRadius10(container_corner_top_radius_px)
UI_CornerRadius01(container_corner_bottom_radius_px)
UI_CornerRadius11(container_corner_bottom_radius_px)
{ {
container = ui_build_box_from_stringf(UI_BoxFlag_Clickable| container = ui_build_box_from_stringf(UI_BoxFlag_Clickable|
UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBorder|
@@ -11108,7 +11104,7 @@ rd_frame(void)
for(HTTP_Response response = {0}; http_pop_response(rd_state->update_check_arena, rd_state->update_check_http_ring, &response, 0);) for(HTTP_Response response = {0}; http_pop_response(rd_state->update_check_arena, rd_state->update_check_http_ring, &response, 0);)
{ {
str8_list_push(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, response.body); str8_list_push(rd_state->update_check_arena, &rd_state->update_check_response_body_pieces, response.body);
if(response.has_more == 0) if(!response.has_more)
{ {
done = 1; done = 1;
} }
@@ -12318,7 +12314,7 @@ rd_frame(void)
}); });
E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0));
expr->type_key = collection_type_key; expr->type_key = collection_type_key;
expr->space = e_space_make(RD_EvalSpaceKind_MetaCtrlEntity); expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery);
e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr);
e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key);
} }
+1
View File
@@ -1020,6 +1020,7 @@ RDI_LocationKindTable:
RDI_SymbolFlagTable: RDI_SymbolFlagTable:
{ {
{IsParam 0x1} {IsParam 0x1}
{IsThunk 0x2}
} }
@table(name type desc) @table(name type desc)
+30
View File
@@ -3194,6 +3194,7 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params)
default:{}break; default:{}break;
case CV_SymKind_LPROC32: case CV_SymKind_LPROC32:
case CV_SymKind_GPROC32: case CV_SymKind_GPROC32:
case CV_SymKind_THUNK32:
{ {
procedure_record_count += 1; procedure_record_count += 1;
scope_record_count += 1; scope_record_count += 1;
@@ -3600,6 +3601,35 @@ p2r_convert(Arena *arena, P2R_ConvertParams *params)
proc_flags = proc32->flags; proc_flags = proc32->flags;
}break; }break;
//- rjf: THUNK32
case CV_SymKind_THUNK32:
{
// rjf: unpack record
CV_SymThunk32 *thunk32 = (CV_SymThunk32 *)iter.struct_base;
String8 name = str8_cstring_capped(thunk32+1, iter.opl);
COFF_SectionHeader *section = (0 < thunk32->sec && thunk32->sec <= coff_sections.count) ? &coff_sections.v[thunk32->sec-1] : 0;
U64 voff_first = 0;
U64 voff_opl = 0;
if(section != 0)
{
voff_first = section->voff + thunk32->off;
voff_opl = voff_first + thunk32->len;
}
// rjf: build symbol / scope
RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, sym_procedures, sym_procedures_chunk_cap);
symbol->name = name;
symbol->is_thunk = 1;
if(voff_first != voff_opl)
{
RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, sym_scopes, sym_scopes_chunk_cap);
RDIM_Rng1U64 range = {voff_first, voff_opl};
rdim_scope_push_voff_range(arena, sym_scopes, scope, range);
scope->symbol = symbol;
symbol->root_scope = scope;
}
}break;
//- rjf: REGREL32 //- rjf: REGREL32
case CV_SymKind_REGREL32: case CV_SymKind_REGREL32:
{ {
+4
View File
@@ -3357,6 +3357,10 @@ rdim_bake(Arena *arena, RDIM_BakeParams *params)
{ {
dst->symbol_flags |= RDI_SymbolFlag_IsParam; dst->symbol_flags |= RDI_SymbolFlag_IsParam;
} }
if(src->is_thunk)
{
dst->symbol_flags |= RDI_SymbolFlag_IsThunk;
}
// rjf: fill container info // rjf: fill container info
if(src->is_extern) if(src->is_extern)
+24 -2
View File
@@ -350,6 +350,18 @@ http_async_tick(void)
req->status_code = status_code; req->status_code = status_code;
} }
// rjf: figure out total bytes
if(req->total_response_bytes == 0)
{
DWORD buffer_size = sizeof(req->total_response_bytes);
WinHttpQueryHeaders(req->hRequest,
WINHTTP_QUERY_CONTENT_LENGTH|WINHTTP_QUERY_FLAG_NUMBER64,
WINHTTP_HEADER_NAME_BY_INDEX,
&req->total_response_bytes,
&buffer_size,
WINHTTP_NO_HEADER_INDEX);
}
// rjf: join all currently read body contents // rjf: join all currently read body contents
String8 body = str8_list_join(scratch.arena, &req->finished_body_pieces, 0); String8 body = str8_list_join(scratch.arena, &req->finished_body_pieces, 0);
@@ -359,7 +371,7 @@ http_async_tick(void)
// rjf: compute size per record header // rjf: compute size per record header
U64 max_record_size = req->out_ring->ring->size; U64 max_record_size = req->out_ring->ring->size;
U64 bytes_per_record_header = sizeof(U64) + sizeof(U64) + sizeof(B32) + sizeof(HTTP_StatusCode); U64 bytes_per_record_header = sizeof(U64) + sizeof(U64) + sizeof(U64) + sizeof(U64) + sizeof(B32) + sizeof(HTTP_StatusCode);
// rjf: push response records // rjf: push response records
for(U64 off = 0, next_off = 0; off <= body.size; off = next_off) for(U64 off = 0, next_off = 0; off <= body.size; off = next_off)
@@ -383,6 +395,8 @@ http_async_tick(void)
B32 has_more = !is_last; B32 has_more = !is_last;
str8_list_push(scratch.arena, &pieces, str8_struct(&record_size)); str8_list_push(scratch.arena, &pieces, str8_struct(&record_size));
str8_list_push(scratch.arena, &pieces, str8_struct(&req->id)); str8_list_push(scratch.arena, &pieces, str8_struct(&req->id));
str8_list_push(scratch.arena, &pieces, str8_struct(&req->total_response_bytes_sent));
str8_list_push(scratch.arena, &pieces, str8_struct(&req->total_response_bytes));
str8_list_push(scratch.arena, &pieces, str8_struct(&has_more)); str8_list_push(scratch.arena, &pieces, str8_struct(&has_more));
str8_list_push(scratch.arena, &pieces, str8_struct(&req->status_code)); str8_list_push(scratch.arena, &pieces, str8_struct(&req->status_code));
str8_list_push(scratch.arena, &pieces, str8_substr(body, r1u64(off, next_off))); str8_list_push(scratch.arena, &pieces, str8_substr(body, r1u64(off, next_off)));
@@ -396,12 +410,18 @@ http_async_tick(void)
if(!guarded_ring_write_string_or_wait(&g, record_data, 0)) if(!guarded_ring_write_string_or_wait(&g, record_data, 0))
{ {
push_failed = 1; push_failed = 1;
String8 unpushed_body_piece = str8_substr(body, r1u64(off, next_off)); String8 unpushed_body_piece = str8_substr(body, r1u64(off, body.size));
str8_list_push(req->arena, &req->finished_body_pieces, str8_copy(req->arena, unpushed_body_piece)); str8_list_push(req->arena, &req->finished_body_pieces, str8_copy(req->arena, unpushed_body_piece));
} }
guarded_ring_close(&g); guarded_ring_close(&g);
} }
// rjf: advance total bytes sent
if(!push_failed)
{
req->total_response_bytes_sent += (next_off - off);
}
// rjf: cancel on no movement // rjf: cancel on no movement
if(next_off == off || push_failed) if(next_off == off || push_failed)
{ {
@@ -528,6 +548,8 @@ http_pop_response(Arena *arena, GuardedRing *out_ring, HTTP_Response *response_o
guarded_ring_read_or_wait(&g, data.size, data.str, max_U64); guarded_ring_read_or_wait(&g, data.size, data.str, max_U64);
U64 off = 0; U64 off = 0;
off += str8_deserial_read_struct(data, off, &response_out->id); off += str8_deserial_read_struct(data, off, &response_out->id);
off += str8_deserial_read_struct(data, off, &response_out->off);
off += str8_deserial_read_struct(data, off, &response_out->off_opl);
off += str8_deserial_read_struct(data, off, &response_out->has_more); off += str8_deserial_read_struct(data, off, &response_out->has_more);
off += str8_deserial_read_struct(data, off, &response_out->code); off += str8_deserial_read_struct(data, off, &response_out->code);
response_out->body.size = (data.size - off); response_out->body.size = (data.size - off);
+2
View File
@@ -35,6 +35,8 @@ struct W32_HTTP_Request
void *optional; // NOTE(rjf): must persist with in-flight requests void *optional; // NOTE(rjf): must persist with in-flight requests
U64 optional_size; U64 optional_size;
HTTP_StatusCode status_code; HTTP_StatusCode status_code;
U64 total_response_bytes_sent;
U64 total_response_bytes;
U64 arena_start_body_read_pos; U64 arena_start_body_read_pos;
String8List finished_body_pieces; String8List finished_body_pieces;
void *next_body_piece; void *next_body_piece;
@@ -201,7 +201,7 @@ smsv_async_tick(void)
{ {
str8_list_push(task->arena, &task->file_pieces, str8_copy(task->arena, r.body)); str8_list_push(task->arena, &task->file_pieces, str8_copy(task->arena, r.body));
} }
if(r.has_more == 0 && task->status != W32_SMSV_TaskStatus_DoneDownloading) if(!r.has_more && task->status != W32_SMSV_TaskStatus_DoneDownloading)
{ {
task->status = W32_SMSV_TaskStatus_DoneDownloading; task->status = W32_SMSV_TaskStatus_DoneDownloading;
W32_SMSV_TaskNode *n = push_array(scratch.arena, W32_SMSV_TaskNode, 1); W32_SMSV_TaskNode *n = push_array(scratch.arena, W32_SMSV_TaskNode, 1);
@@ -329,6 +329,11 @@ smsv_async_tick(void)
} }
} }
write_data_list_to_file_path(task->local_path, task->file_pieces); write_data_list_to_file_path(task->local_path, task->file_pieces);
if(task->current_server_url_node != 0)
{
String8 origin_path = str8f(scratch.arena, "%S/origin.txt", str8_chop_last_slash(task->local_path));
write_data_to_file_path(origin_path, task->current_server_url_node->string);
}
} }
// rjf: evict task from cache // rjf: evict task from cache