| 319 | } |
| 320 | |
| 321 | fn write_with_cursor( |
| 322 | &self, |
| 323 | cursor_id: u64, |
| 324 | buf: &[u8], |
| 325 | append: bool, |
| 326 | ) -> Result<u64, BufIoError> { |
| 327 | let curr_pos = { |
| 328 | let cursors = self.cursors.read().map_err(|_| BufIoError::Locking)?; |
| 329 | let cursor = cursors |
| 330 | .get(&cursor_id) |
| 331 | .ok_or(BufIoError::InvalidCursor(cursor_id))?; |
| 332 | cursor.position |
| 333 | }; |
| 334 | |
| 335 | let input_size = buf.len(); |
| 336 | |
| 337 | // Take write lock early to cover the entire write operation that might affect file size |
| 338 | let mut file_size_guard = self.file_size.write().map_err(|_| BufIoError::Locking)?; |
| 339 | let will_cross_eof = append || curr_pos + input_size as u64 >= *file_size_guard; |
| 340 | let mut curr_pos = if append { |
| 341 | curr_pos.max(*file_size_guard) |
| 342 | } else { |
| 343 | curr_pos |
| 344 | }; |
| 345 | let start_pos = curr_pos; |
| 346 | |
| 347 | if will_cross_eof { |
| 348 | let mut total_written = 0; |
| 349 | while total_written < input_size { |
| 350 | let region = self.get_or_create_region(curr_pos)?; |
| 351 | { |
| 352 | let mut buffer = region.buffer.write().map_err(|_| BufIoError::Locking)?; |
| 353 | let buffer_pos = (curr_pos - region.start) as usize; |
| 354 | let available = self.buffer_size - buffer_pos; |
| 355 | let to_write = (input_size - total_written).min(available); |
| 356 | buffer[buffer_pos..buffer_pos + to_write] |
| 357 | .copy_from_slice(&buf[total_written..total_written + to_write]); |
| 358 | region.end.store( |
| 359 | (buffer_pos + to_write).max(region.end.load(Ordering::SeqCst)), |
| 360 | Ordering::SeqCst, |
| 361 | ); |
| 362 | region.dirty.store(true, Ordering::SeqCst); |
| 363 | total_written += to_write; |
| 364 | curr_pos += to_write as u64; |
| 365 | } |
| 366 | } |
| 367 | // Update file size using max to prevent shrinking |
| 368 | *file_size_guard = (*file_size_guard).max(curr_pos); |
| 369 | } else { |
| 370 | // Normal write within existing file bounds |
| 371 | let mut total_written = 0; |
| 372 | while total_written < input_size { |
| 373 | let region = self.get_or_create_region(curr_pos)?; |
| 374 | { |
| 375 | let mut buffer = region.buffer.write().map_err(|_| BufIoError::Locking)?; |
| 376 | let buffer_pos = (curr_pos - region.start) as usize; |
| 377 | let available = self.buffer_size - buffer_pos; |
| 378 | let to_write = (input_size - total_written).min(available); |