参考所有分组,完成尽量多的内容。禁止顺手扩功能 smoke:锁定OPFS参数保存顺序

结论:按 LinuxCNC rs274ngc_pre.cc save_parameters() 的 .new、.bak、unlink/link/rename 顺序补强 OPFS/app/browser smoke 守卫,并验证临时参数文件不会残留在 OPFS。
This commit is contained in:
cnc
2026-06-04 19:42:49 +08:00
parent a12c0166b5
commit b89d6311ff
7 changed files with 46 additions and 0 deletions

View File

@@ -23,6 +23,12 @@ grep -F 'std::string tempfile = std::string(filename) + ".new";' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \ grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'unlink(bakfile.c_str());' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \ grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
@@ -33,6 +39,8 @@ grep -F '`RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
docs/linuxcnc-browser-app-source-map.md >/dev/null docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F '`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`' \ grep -F '`parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", ...)`' \
docs/linuxcnc-browser-app-source-map.md >/dev/null docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F 'orders parameter saves as backup unlink' \
docs/linuxcnc-browser-app-source-map.md >/dev/null
grep -F '<script type="module" src="/src/app.js"></script>' web/index.html >/dev/null grep -F '<script type="module" src="/src/app.js"></script>' web/index.html >/dev/null
grep -F '<option value="linuxcnc-rs274">LINUXCNC</option>' web/index.html >/dev/null grep -F '<option value="linuxcnc-rs274">LINUXCNC</option>' web/index.html >/dev/null
@@ -63,6 +71,8 @@ grep -F 'app frame did not persist LinuxCNC parameter state into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \ grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'OPFS PROGRAM RESTORED' web/test-browser-wasm-smoke-app-sections.js >/dev/null grep -F 'OPFS PROGRAM RESTORED' web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not reload LinuxCNC parameter state from OPFS after reload' \ grep -F 'app frame did not reload LinuxCNC parameter state from OPFS after reload' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null web/test-browser-wasm-smoke-app-sections.js >/dev/null

View File

@@ -22,6 +22,12 @@ grep -F 'std::string tempfile = std::string(filename) + ".new";' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \ grep -F '+ RS274NGC_PARAMETER_FILE_BACKUP_SUFFIX;' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'unlink(bakfile.c_str());' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \ grep -F 'RS274NGC_PARAMETER_FILE_NAME_DEFAULT` as `rs274ngc.var`' \
docs/linuxcnc-opfs-source-map.md >/dev/null docs/linuxcnc-opfs-source-map.md >/dev/null
@@ -31,6 +37,8 @@ grep -F '`Interp::restore_parameters()` for parameter-file reads' \
docs/linuxcnc-opfs-source-map.md >/dev/null docs/linuxcnc-opfs-source-map.md >/dev/null
grep -F '`Interp::save_parameters()` for `filename + ".new"`' \ grep -F '`Interp::save_parameters()` for `filename + ".new"`' \
docs/linuxcnc-opfs-source-map.md >/dev/null docs/linuxcnc-opfs-source-map.md >/dev/null
grep -F 'unlinks `filename + ".bak"`, links the' \
docs/linuxcnc-opfs-source-map.md >/dev/null
grep -F 'must not add independent filesystem behavior or expand the temporary smoke parser' \ grep -F 'must not add independent filesystem behavior or expand the temporary smoke parser' \
docs/linuxcnc-opfs-source-map.md >/dev/null docs/linuxcnc-opfs-source-map.md >/dev/null
grep -F 'parseFileWithParameterFile()' docs/linuxcnc-opfs-source-map.md >/dev/null grep -F 'parseFileWithParameterFile()' docs/linuxcnc-opfs-source-map.md >/dev/null
@@ -47,6 +55,8 @@ grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.new`' web/src/wasm-core.js >/dev/nu
grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.bak`' web/src/wasm-core.js >/dev/null grep -F '`${LINUXCNC_DEFAULT_PARAMETER_FILE}.bak`' web/src/wasm-core.js >/dev/null
grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters() reads the' web/src/wasm-core.js >/dev/null grep -F 'LinuxCNC source basis: rs274ngc_pre.cc restore_parameters() reads the' web/src/wasm-core.js >/dev/null
grep -F 'before replacing the main file and managing filename + ".bak".' web/src/wasm-core.js >/dev/null grep -F 'before replacing the main file and managing filename + ".bak".' web/src/wasm-core.js >/dev/null
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'OPFS cannot be disabled in browser contexts with OPFS support' web/src/wasm-core.js >/dev/null grep -F 'OPFS cannot be disabled in browser contexts with OPFS support' web/src/wasm-core.js >/dev/null
grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \ grep -F 'const events = await simulator.parseFileWithParameterFile(programPath, parameterPath, "linuxcnc", parseOptions);' \
web/src/app.js >/dev/null web/src/app.js >/dev/null
@@ -83,6 +93,7 @@ required_phrases = [
"parameters/rs274ngc.var", "parameters/rs274ngc.var",
"LinuxCNC `read_text()`", "LinuxCNC `read_text()`",
"`.new`, `.bak`, failure, and stale-state semantics", "`.new`, `.bak`, failure, and stale-state semantics",
'unlinks `filename + ".bak"`',
"OPFS/WASM mirror persistence", "OPFS/WASM mirror persistence",
"app-level OPFS program, parameter, backup, and reload behavior", "app-level OPFS program, parameter, backup, and reload behavior",
] ]

View File

@@ -19,6 +19,12 @@ grep -F 'int Interp::save_parameters(const char *filename,' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'std::string tempfile = std::string(filename) + ".new";' \ grep -F 'std::string tempfile = std::string(filename) + ".new";' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'unlink(bakfile.c_str());' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(link(filename, bakfile.c_str()) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'if(rename(tempfile.c_str(), filename) < 0)' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \ grep -F 'read_text(command, _setup.file_pointer, _setup.linetext,' \
"$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null "$linuxcnc_root/src/emc/rs274ngc/rs274ngc_pre.cc" >/dev/null
grep -F 'int read_text(const char *command, FILE * inport, char *raw_line,' \ grep -F 'int read_text(const char *command, FILE * inport, char *raw_line,' \
@@ -51,6 +57,7 @@ grep -F 'must not expand the temporary smoke parser' docs/linuxcnc-wasm-smoke-so
grep -F 'OPFS-only' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null grep -F 'OPFS-only' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
grep -F '`src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage' \ grep -F '`src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage' \
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
grep -F 'unlinking `filename + ".bak"`' docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
grep -F '`src/emc/kinematics/5axiskins.c`, `src/emc/kinematics/trtfuncs.c`' \ grep -F '`src/emc/kinematics/5axiskins.c`, `src/emc/kinematics/trtfuncs.c`' \
docs/linuxcnc-wasm-smoke-source-map.md >/dev/null docs/linuxcnc-wasm-smoke-source-map.md >/dev/null
grep -F 'Generated switchkins config smoke cases must continue to come from' \ grep -F 'Generated switchkins config smoke cases must continue to come from' \
@@ -102,6 +109,8 @@ grep -F 'app frame did not persist current program into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \ grep -F 'app frame did not persist LinuxCNC parameter backup into OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null web/test-browser-wasm-smoke-app-sections.js >/dev/null
grep -F 'app frame did not clean up LinuxCNC temporary parameter file in OPFS' \
web/test-browser-wasm-smoke-app-sections.js >/dev/null
if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then if grep -R -n -E 'localStorage|sessionStorage|indexedDB|showOpenFilePicker|showSaveFilePicker|showDirectoryPicker|webkitRequestFileSystem|FileReader' web/src; then
echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2 echo "browser app/wasm code must not add filesystem persistence outside OPFS" >&2
@@ -145,6 +154,7 @@ required_phrases = [
"Node smoke must leave OPFS disabled", "Node smoke must leave OPFS disabled",
"Generated switchkins config smoke cases", "Generated switchkins config smoke cases",
"browser smoke shell guard also pins required section names", "browser smoke shell guard also pins required section names",
'unlinking `filename + ".bak"`',
"./check-linuxcnc-wasm-smoke-source-map.sh", "./check-linuxcnc-wasm-smoke-source-map.sh",
] ]
for phrase in required_phrases: for phrase in required_phrases:

View File

@@ -15,6 +15,8 @@ must not expand the temporary smoke parser.
- `src/emc/rs274ngc/rs274ngc_pre.cc` saves parameter files through - `src/emc/rs274ngc/rs274ngc_pre.cc` saves parameter files through
`Interp::save_parameters()`, including `filename + ".new"` and `Interp::save_parameters()`, including `filename + ".new"` and
`filename + ".bak"` behavior. `filename + ".bak"` behavior.
- `src/emc/rs274ngc/rs274ngc_pre.cc` orders parameter saves as backup unlink,
backup link, then temporary-file rename.
- `src/emc/rs274ngc/rs274ngc_pre.cc` reads program blocks through `read_text()` - `src/emc/rs274ngc/rs274ngc_pre.cc` reads program blocks through `read_text()`
after the browser bridge mirrors the OPFS program into the WASM filesystem. after the browser bridge mirrors the OPFS program into the WASM filesystem.

View File

@@ -14,6 +14,9 @@ persistence. It is a policy and bridge map only; it must not add independent fil
- `src/emc/rs274ngc/rs274ngc_pre.cc` implements - `src/emc/rs274ngc/rs274ngc_pre.cc` implements
`Interp::save_parameters()` for `filename + ".new"`, backup, and replacement `Interp::save_parameters()` for `filename + ".new"`, backup, and replacement
writes. writes.
- `src/emc/rs274ngc/rs274ngc_pre.cc` unlinks `filename + ".bak"`, links the
previous parameter file to that backup path, then renames `filename + ".new"`
over the configured parameter file.
## OPFS Coverage ## OPFS Coverage

View File

@@ -11,6 +11,9 @@ OPFS-only is the required boundary.
- `src/emc/rs274ngc/rs274ngc_pre.cc` provides `Interp::ini_load()`, - `src/emc/rs274ngc/rs274ngc_pre.cc` provides `Interp::ini_load()`,
`Interp::restore_parameters()`, `Interp::save_parameters()`, and `read_text()` `Interp::restore_parameters()`, `Interp::save_parameters()`, and `read_text()`
behavior exercised by Node/browser bridge tests. behavior exercised by Node/browser bridge tests.
- `src/emc/rs274ngc/rs274ngc_pre.cc` saves parameters by writing
`filename + ".new"`, unlinking `filename + ".bak"`, linking the previous file
to `filename + ".bak"`, and renaming the temporary file over the main file.
- `src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage for - `src/emc/rs274ngc/interp_convert.cc` provides `convert_m()` coverage for
M66 waits and M68 analog output side effects used by generated remap cases. M66 waits and M68 analog output side effects used by generated remap cases.
- `src/emc/nml_intf/canon.hh` declares the `WAIT()` and - `src/emc/nml_intf/canon.hh` declares the `WAIT()` and

View File

@@ -39,6 +39,13 @@ export async function runBrowserAppOpfsSections(context) {
const updatedParameterFile = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var")); const updatedParameterFile = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var"));
expectIncludes(updatedParameterFile, "5161\t2.000000", expectIncludes(updatedParameterFile, "5161\t2.000000",
"app frame did not replace LinuxCNC parameter state after second parse"); "app frame did not replace LinuxCNC parameter state after second parse");
// LinuxCNC source basis: rs274ngc_pre.cc save_parameters()
// renames filename + ".new" over filename after a successful save.
await context.expectOpfsMissing(
appSimulator,
"parameters/rs274ngc.var.new",
"app frame did not clean up LinuxCNC temporary parameter file in OPFS",
);
const savedParameterBackup = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var.bak")); const savedParameterBackup = new TextDecoder().decode(await appSimulator.fs.opfs.readFile("parameters/rs274ngc.var.bak"));
expectIncludes(savedParameterBackup, "5161\t1.000000", expectIncludes(savedParameterBackup, "5161\t1.000000",
"app frame did not persist LinuxCNC parameter backup into OPFS"); "app frame did not persist LinuxCNC parameter backup into OPFS");