Repository navigation
Release v1.7.2: SOLID refactor, fixes, docs - #16
Merged
Merged
Conversation
…ed files (P6, no logic change) Pure move: the data tables, the hint UI and find_holder, read_options / enable_options, work_area / patch_vb_screen_walk and the PEGRC redirect (plus clear_runasinvoker) now live in src/dynafix_*.inc.c, #included from dynafix.c at the place the code used to be. Still one compilation unit (tests/logtest.c includes dynafix.c); build.cmd is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter (applog.h) Header-only src/applog.h (static functions, build.cmd unchanged): make_sa and its SDDL, the dynafix.log mutex and append, now() and DAY, the HKCU Update* value names and the launcher <-> setup command-line verbs. launcher.c and update.c use it. Mutex name, line format, trim threshold and line length limits are unchanged; only the launcher trims, as before. dynafix.dll keeps its own copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Release v1.7.1
One flow for both ways a noted release is offered: BEFORE_DYNARUN (/update: Yes/No, DynaRun not running, launcher started afterwards) and BESIDE_DYNARUN (/offer: Yes/No/Cancel beside the running DynaRun, install once it is closed). Texts, buttons, log lines, registry writes and their order are unchanged; update_run and update_offer keep their signatures. The repeated RegDeleteValueW blocks become clear_note(k, skip). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt_le, start_plain and hook_and_finish Code moved as it was: "/wasadmin" is still taken before the elevation check, log_start still runs before "/noupdate", "/autostart" and "/restart" are parsed, and the start order (attach / notice / dll load / LE or plain / hook) is the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d result codes Locks today's behaviour: the switch parsing of setup.c and driver_verb, the argument string run_elevated builds (ShellExecuteEx stubbed), FIX_DONE for 0..40 and the PK_/DRV_/RC_ values. The two parsing loops are moved unchanged into static helpers (parse_switches, prep_accept_arg) so they can be called; no behaviour change. test_hardening.c gets the missing driver_prep_stage stub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the tests Neither function has a caller in the shipped exe: the installer no longer copies COM registrations (promote_com_in, with reg_export, skipped and g_export_root, only used by it), and nothing unpacks a whole zip (zip_extract_all, xall_visit, make_dirs, ZIP_MAX_*). They now live in tests\promote_com.h (included by test_hardening.c) and tests\zip_extract_all.h (included by test_driver.c), so the tests that use them keep compiling and the code does not rot. No change to the shipped behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…b only The button on the "DynaRun is running" page set g_close to TRUE and nothing ever reset it. run_elevated forwards g_close as /close to every later elevated stage, and the stage then ends a running DynaRun with TerminateProcess without asking. So after one consent, a retry (UAC cancelled, install failed) that met a DynaRun started during the UAC prompt killed it instead of returning RC_RUNNING and showing the page again; running_early also skipped its check. The button now records that it set the flag (g_close_asked) and job_done takes it back when that job has ended. A /close given on the command line is not touched. The text check of wizard.c in test_driver.c covers both places. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since the installer stopped copying COM registrations, the whole check machinery that promote_com_in used stayed behind in src/setup.c with no shipped caller: add_key, free_keys, has_key, g_keys/g_ids/g_kinds/g_nkeys, com_roots, g_com_nfolder, under, com_path_ok, value_state, has_subkey, clsid_ok, progid_ok, typelib_ok, typelib_complete, copy_tree and delete_key_tree. They are only compiled into the shipped installer, never called. Move them to tests/promote_com.h, which test_hardening.c already includes after setup.c, so the same checks are still exercised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…en held peg_ldr_note patched through patch_base without the busy flag peg_check uses, so on two threads both could modify a hook_t's raw/chain at once. The flag is now file-scope and shared; the callback only try-acquires it (it runs under the loader lock and must not wait). When it is taken, the callback sets a pending flag and logs nothing; peg_check then forgets its per-module bookkeeping and patches the loaded modules again (idempotent). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New src/errors.h (included by setup.h) holds every result code: RC_* for the install/uninstall result and process exit code (RC_OK, RC_FAIL, RC_CANCEL, RC_OVER_SHOULDER, RC_MSI_FAILED, RC_NO_DYNARUN, RC_RUNNING), PK_*, PKC_* (file check status), DRV_*, and small enums for the pin result, the update hint, the BitLocker answer and remove_dynarun's "not installed". Bare 2/3/4/5 in setup.c, wizard.c, package.c and driver.c now use the name of their own meaning (cancel 2 vs PK_NET 2, RC_RUNNING 6 vs PK_PASSWORD 6 stay separate). FIX_DONE moves to errors.h with the done codes listed; same truth value for every int. The compiled code is identical (checked by disassembly). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup.c now defines (declared in setup.h) path_join (dir + name with the old `lstrlen + 2 >= limit` test), run_process (CreateProcess + wait with timeout), dir_walk (one folder level with a callback; skips '.' names and too long paths) and app_key_open / app_key_create (HKCU\Software\DynaRunFix, HKLM\SOFTWARE\DynaRunFix). Used by package.c (scan, find_zip_in, find_dir_in, hydrate_tree, the msiexec calls, the registry notes), driver.c (run_tool, the BitLocker flag, two joins) and setup.c (delete_tree, the lnk name check, the install keys). The four shortcut walks in setup.c and the differing process starts (run_tool_to_file, touch, run_elevated) are left as they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…globals g_quiet, g_close, g_pin, g_autostart, g_autostart_later and g_keep become the fields of install_opts. The command line fills one in main, the wizard owns one (and hands each job a copy, taken in start_job) and run_elevated builds its forwarded switches from the struct it is given: no hidden dependency on globals. Same switches in the same order (<args> /quiet /close /pin /keep). The wizard's "close DynaRun" consent (g_close_asked) still covers one install job only. g_pinresult was a result, not an option: it is install_result.pin, written by the user stage and read by the wizard once the job is done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup.c's if/else chain on argv[1] and driver.c's driver_verb become one table
{name, min_args, handler} (VERBS); driver.c supplies the handlers of its five
verbs. The command line is parsed once (cmd_parse) into a cmdline struct.
Verbs, argument positions, the argc needed (/machine, /full: 4) and exit codes
are unchanged.
/unverified keeps its two rules, now computed by the same loop: daccept (any
position from argv[4], the last valid one: /machine, /full) and daccept4 (only
argv[4] argv[5]: /driver-prep). The setup builds /unverified at argv[4]
(/driver-prep) or argv[6] (/machine, /full) where both agree; they differ only
for hand-typed lines (a valid /unverified after another switch, or two of them),
which the tests lock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shell folders that can hold a DynaRun shortcut were listed in six places (icon search, fix, point-back, search for our own shortcut, restore path check, other accounts' point-back). They are now one table (SF[]) with a flag per use and a deep flag per use, read through shortcut_folders(); each user keeps exactly the folders and recursion it had. The four walks (find_icon, scan, find_ours, unretarget) use dir_walk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…verflowing The unified sf_path() now always checks the length of the %APPDATA% path before the sub folder is appended. Until now only the uninstall's point-back (unretarget_shell) and the restore path check (lnk_path_ok) did; fix_shortcuts, desktop_link, pin_taskbar, pinned_ours and the creation of the DynaRunFix shortcut appended "\Microsoft\Internet Explorer\Quick Launch" or "\DynaRunFix" to a d[MAX_PATH] buffer without looking, so an %APPDATA% path of about 210 characters or more overflowed it. Before: those callers wrote past the end of the buffer for such a profile. After: the folder is skipped (fix_shortcuts does not scan the Quick Launch folder, desktop_link/pin_taskbar report that there is none to use). A shorter path behaves as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st and the MSI API g_user_sid and g_exe_trusted are now a trust_ctx that each stage makes and passes to user_writable, check_exe and g_is_writable (path_user_writable makes its own from the sid it is given). The MSI function pointers are looked up by one idempotent msi_api_init(), called by classify before its check of advertised shortcuts, so classify no longer depends on fix_shortcuts having run first. The tests pass a trust_ctx of their own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nit) src\setup.c keeps the header comment, the system includes and the entry point; the rest moved unchanged, in the original order, into src\setup\*.h (defs, util, stage, trust, exetime, procs, shortcuts, taskbar, users, machine, elevate, msi_stage, userstage, uninstall, cmdline). They are fragments of the same translation unit: build.cmd and the tests still compile and include only setup.c. Object code of setup.c is identical before and after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zip_open and zip_walk each had their own copy of the end-of-central-directory scan, the central directory read and the entry field decoding. They now share zipcd_load (EOCD scan + directory read) and zipent_fill (entry fields + local header); the per-reader rules stay where they were: zip_walk still refuses Zip64 markers and any damaged entry, zip_open still takes the first .msi and ignores the entry count. crc_init is one idempotent entry point (done flag set after the table is complete) called by zipcd_load, zip_extract and zip_password_plausible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
run_tool_ok takes the tolerated exit code and its meaning as arguments (run_tool is the plain form), replacing g_tool_ok_code / g_tool_ok_text. The zip and folder searches take a pkg_search (accept callback with a context, and the log function), replacing g_pkg_log. The first folder with all 18 files of which some differ is now the folder search's own result (known_ctx.other, replacing g_other_dir); that needed one callback context for both candidate kinds, so zip_known_cb and dir_known_cb became one known_cb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every return after the argument checks is now 'set res, goto out'; the exit does the cleanup the former return sites did inline (remove base\driver, cancel_locked, bde_resume), so the leftovers are exactly the same as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fails
prep_locked, first attempt (a zip or folder is given, the staging folder was
just made by make_base), now removes <ProgramData>\DynaRunFix\driver\ and
accepted.txt on these failures, which used to leave them behind:
- staged_ok fails after staging (DRV_E_INF)
- copying the setup exe into the folder fails (DRV_E_COPY)
- bcdedit fails (DRV_E_BCD; accepted.txt was not removed there either)
- the task XML cannot be written or schtasks fails (DRV_E_TASK; cancel_locked
already removed accepted.txt, the staged tree stayed)
Nothing is armed at those points and every later attempt stages again
(make_base wipes the folder), so nothing can use the leftovers; the other
staging failures (extract, hash, not accepted) already dropped the tree.
Unchanged on purpose: a retry (zip "-", the staged files from the first
attempt, task armed) keeps its staged files on DRV_E_INF and DRV_E_COPY;
success and DRV_W_BDE keep everything.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
drf_app.h (language, paths, options, command line, basic helpers, install entry points), drf_util.h (path_join, run_process, dir_walk, app key, the elevated-stage helpers), drf_package.h, drf_driver.h, drf_update.h, drf_wizard.h. Declarations used only by the tests moved to drf_package_internal.h and drf_driver_internal.h. The drf_ prefix keeps the names apart from src\setup\util.h. setup.h includes the public headers so update.c is unchanged. Declarations only moved; the generated code is identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JOBS[] holds, per job, the worker proc, the on_done handler and the two flags that used to be enum-order comparisons (keep the wizard behind the UAC/msiexec windows, bring it back to the front when done). job_proc and job_done no longer switch. test_job_table checks the table: a row with proc and on_done for every job, procs that return outside a comment, job_done still takes the close consent back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ombination g_flow (FLOW_MAIN, FLOW_MAIN_WITH_DRIVER, FLOW_DRIVER_ONLY, FLOW_DRIVER_CONTINUE) replaces g_pre, g_driver_only and the later reads of g_drvmode, which is now read once at the start of wizard(). g_fix_done stays: it is progress, not flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
set_page (a 350-line switch) is split into one enter_<page> function per page, and PAGES[] has one row per page: enter, primary, second, third, extra, the close hook, the page's Alt+key shortcuts and PF_NOCLOSE. on_primary, on_second, on_third, ID_EXTRA, on_close and the Alt+key handling in the message loop go through the row. A new page is a P_* value, an enter_* function and a row. Behaviour is unchanged: every page keeps the same buttons, texts, shortcuts and close behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
g_result is the process exit code of wizard(). It is RC_CANCEL until a page decides otherwise: the success pages (Done, driver installed, restart for the driver) set RC_OK, the error pages (acquire error, "Something went wrong", "The driver was not installed") set RC_FAIL; set_page takes it back to RC_CANCEL first. wizard() returns it instead of testing g_page. Every exit code is the one the old page mapping gave. The install_result that held the name is now g_instres. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unit) wizard.c keeps the includes, the ids, the enums and the state; the code is in src\wizard\layout.h (UI helpers, screenshots, controls, layout), acquire.h (getting the DynaRun setup and the driver package: download, password, check, license), driver.h (the driver pages and jobs) and main.h (the main flow, JOBS[], PAGES[], the window procedure, wizard()). They are fragments of the same translation unit, like src\setup\*.h; build.cmd is unchanged. Only the order of the functions and a few forward declarations in wizard.c differ: every function compiles to the same code. tests: test_job_table() reads wizard.c and the four fragments as one text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wizard's state is one UI-owned wizard_state (wz). A job gets a job_in copied by start_job (like the old g_jobopts) and writes only a job_out; job_done merges the part the job produced (JOBS[].merge) after the join. The hint thread writes its own hint_out before it posts WM_HINT. test_job_table follows the new names and checks that no job proc touches wz. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
on_progress remembers the last percentage it posted (lastpct) so that it posts only when the value changes. The UI's progress() used to reset that value too, from the UI thread while the worker could be inside on_progress. Now start_job sets it before the worker exists and only the worker changes it afterwards. The race was benign (an int store that at worst made one more or one fewer identical update get through), but the visible difference is that with an unknown download size (percentage 0 throughout) the UI's reset on a page or marquee change let a second or third update through; now the progress bar gets exactly one update per value. The bar position is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wizard's 208 T(en, zh) calls (169 different pairs) become TX(S_...) over one table, UI_STR in src/wizard/strings.h; the setup's 29 calls (27 pairs) become TS(ST_...) over SETUP_STR in src/setup/strings.h. Exact duplicates (Cancel, Close, Open website ...) are in a table once. The texts are moved unchanged: the sequence of pairs used and the strings in wizard.obj / setup.obj are identical to before. setup.rc is untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…it, dynafix split, applog)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sf_path() now takes the number of characters the caller appends afterwards (the pinned-items folder, the shortcut file name) and skips the folder when the result would not fit in MAX_PATH. The check is split into sf_fit() so that test_hardening can exercise it with any path length. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The message parameter was used as an index into JOBS[] unchecked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment only. The branch that wins the busy flag calls logf (log mutex, at most 2 s) and patch_base; only the flag itself is never waited for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Internal refactor with no intended behaviour change (setup/wizard/driver/package split into modules, named result codes, install options passed explicitly, verb/page/job tables, launcher and update share one log helper, dynafix split into include files), plus fixes:
Docs aligned (CHANGELOG v1.7.2, manual version entries, refactor record, tests/README, VM checklist). Unit tests and the VM regression checklist passed on the merged refactor; the follow-up fixes are covered by unit tests in CI, the installer smoke test on the final build was not run.
🤖 Generated with Claude Code