fix(io): handle file shrink in update_for_append to prevent SIGBUS
File truncation/rotation during mmap lifetime caused SIGBUS crash because update_for_append() ignored new_size < old_size, leaving a stale mapping that would fault on access. Introduce AppendStatus enum (Unchanged/Appended/Reloaded) so the caller can distinguish shrink events from normal appends. On shrink, reload() rebuilds the mmap and line index. The TUI layer clamps cursor and invalidates viewport cache on Reloaded, matching the existing handle_file_truncated() behavior. Fixes #1
This commit is contained in:
@@ -859,43 +859,58 @@ impl App {
|
||||
let width = self.get_content_width();
|
||||
match &mut self.loading_state {
|
||||
AppLoadingState::Ready { reader } => {
|
||||
if let Ok(_new_lines) = reader.update_for_append() {
|
||||
let _ = reader.save_cache();
|
||||
let status = reader.update_for_append();
|
||||
match status {
|
||||
Ok(
|
||||
log_viewer_core::io::file_reader::AppendStatus::Appended(_new_lines),
|
||||
) => {
|
||||
let _ = reader.save_cache();
|
||||
|
||||
let (old_line_count, can_extend) = {
|
||||
match &reader.state {
|
||||
log_viewer_core::io::progressive_reader::ReaderState::Ready {
|
||||
visual_height_index: Some(idx),
|
||||
..
|
||||
} => (idx.line_count(), idx.is_valid_for(self.json_format, width)),
|
||||
_ => (0, false),
|
||||
}
|
||||
};
|
||||
let new_line_count = reader.line_count();
|
||||
|
||||
if can_extend && new_line_count > old_line_count {
|
||||
if let log_viewer_core::io::progressive_reader::ReaderState::Ready {
|
||||
visual_height_index: Some(index),
|
||||
reader: fr,
|
||||
} = &mut reader.state
|
||||
{
|
||||
let mut new_heights = Vec::with_capacity(new_line_count - old_line_count);
|
||||
for i in old_line_count..new_line_count {
|
||||
let line_text = fr.get_line(i).unwrap_or("");
|
||||
new_heights.push(compute_line_visual_height(
|
||||
line_text,
|
||||
width,
|
||||
self.json_format,
|
||||
));
|
||||
let (old_line_count, can_extend) = {
|
||||
match &reader.state {
|
||||
log_viewer_core::io::progressive_reader::ReaderState::Ready {
|
||||
visual_height_index: Some(idx),
|
||||
..
|
||||
} => (idx.line_count(), idx.is_valid_for(self.json_format, width)),
|
||||
_ => (0, false),
|
||||
}
|
||||
index.extend_from_heights(&new_heights);
|
||||
};
|
||||
let new_line_count = reader.line_count();
|
||||
|
||||
if can_extend && new_line_count > old_line_count {
|
||||
if let log_viewer_core::io::progressive_reader::ReaderState::Ready {
|
||||
visual_height_index: Some(index),
|
||||
reader: fr,
|
||||
} = &mut reader.state
|
||||
{
|
||||
let mut new_heights = Vec::with_capacity(new_line_count - old_line_count);
|
||||
for i in old_line_count..new_line_count {
|
||||
let line_text = fr.get_line(i).unwrap_or("");
|
||||
new_heights.push(compute_line_visual_height(
|
||||
line_text,
|
||||
width,
|
||||
self.json_format,
|
||||
));
|
||||
}
|
||||
index.extend_from_heights(&new_heights);
|
||||
}
|
||||
} else {
|
||||
reader.invalidate_visual_height_index();
|
||||
reader.start_visual_height_rebuild(width, self.json_format);
|
||||
}
|
||||
} else {
|
||||
|
||||
self.viewport_cache.invalidate();
|
||||
}
|
||||
Ok(log_viewer_core::io::file_reader::AppendStatus::Reloaded) => {
|
||||
let _ = reader.save_cache();
|
||||
reader.invalidate_visual_height_index();
|
||||
reader.start_visual_height_rebuild(width, self.json_format);
|
||||
self.cursor_line = self.cursor_line.min(self.total_lines().saturating_sub(1));
|
||||
self.v_sub_offset = 0;
|
||||
self.viewport_cache.invalidate();
|
||||
self.clamp_v_offset();
|
||||
}
|
||||
|
||||
self.viewport_cache.invalidate();
|
||||
Ok(log_viewer_core::io::file_reader::AppendStatus::Unchanged) | Err(_) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -911,7 +926,9 @@ impl App {
|
||||
reader.invalidate_visual_height_index();
|
||||
reader.start_visual_height_rebuild(width, self.json_format);
|
||||
self.cursor_line = self.cursor_line.min(self.total_lines().saturating_sub(1));
|
||||
self.v_sub_offset = 0;
|
||||
self.viewport_cache.invalidate();
|
||||
self.clamp_v_offset();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user