mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix: lock sync's first inspection, resolve symlinks without their target
Fourth Codex (gpt-6.1-sol, xhigh) pass over 5e0831d, each item verified
before fixing:
- sync inspects the local database under the shared lock, so another
sync cannot swap it under that connection.
- symlinks are resolved by reading the link (db::resolve_db_path), not
canonicalize, so a symlinked path finds the same lock and install
target even while the real file is missing (fresh install, mid-swap)
or the link dangles.
- readers go ahead unlocked when no lock file can be created; nothing
can replace the database there. (A read-only data directory still
fails in SQLite's WAL setup, as in 0.2.4.)
- XLSX shared strings are capped at 2,000,000 entries.
Verified live: an install waits for a reader's shared lock; a symlinked
db_path waits on the real path's lock and stays a symlink. CLI goldens
unchanged; live A/B vs 0.2.4: 16 passed, discover hits the IDX 403 on
both builds (exit 4 vs 1, intended).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5e0831d8fe
commit
c65982f407
4 changed files with 111 additions and 25 deletions
|
|
@ -127,7 +127,10 @@ fn parse_shared_strings(xml: &str) -> Result<Vec<String>, IdxError> {
|
|||
b"rPh" => in_phonetic = true,
|
||||
_ => {}
|
||||
},
|
||||
Ok(Event::Empty(e)) if e.local_name().as_ref() == b"si" => strings.push(String::new()),
|
||||
Ok(Event::Empty(e)) if e.local_name().as_ref() == b"si" => {
|
||||
check_shared_string_count(strings.len())?;
|
||||
strings.push(String::new())
|
||||
}
|
||||
Ok(Event::Text(text)) if in_text && !in_phonetic => {
|
||||
if let Some(value) = current.as_mut() {
|
||||
let unescaped = text
|
||||
|
|
@ -137,7 +140,10 @@ fn parse_shared_strings(xml: &str) -> Result<Vec<String>, IdxError> {
|
|||
}
|
||||
}
|
||||
Ok(Event::End(e)) => match e.local_name().as_ref() {
|
||||
b"si" => strings.push(current.take().unwrap_or_default()),
|
||||
b"si" => {
|
||||
check_shared_string_count(strings.len())?;
|
||||
strings.push(current.take().unwrap_or_default())
|
||||
}
|
||||
b"t" => in_text = false,
|
||||
b"rPh" => in_phonetic = false,
|
||||
_ => {}
|
||||
|
|
@ -184,6 +190,18 @@ fn text_cap_error() -> IdxError {
|
|||
)
|
||||
}
|
||||
|
||||
const MAX_SHARED_STRINGS: usize = 2_000_000;
|
||||
|
||||
fn check_shared_string_count(count: usize) -> Result<(), IdxError> {
|
||||
if count >= MAX_SHARED_STRINGS {
|
||||
return Err(xml_error(
|
||||
"shared strings",
|
||||
format!("more than {MAX_SHARED_STRINGS} entries"),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_row_count(rows: usize) -> Result<(), IdxError> {
|
||||
if rows >= MAX_SHEET_ROWS {
|
||||
return Err(xml_error(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue