casc_storage/archive/
archive_writer.rs1use crate::error::Result;
4use std::fs::{File, OpenOptions};
5use std::io::{BufWriter, Seek, SeekFrom, Write};
6use std::path::Path;
7use tracing::debug;
8
9pub struct ArchiveWriter {
11 writer: BufWriter<File>,
12 current_offset: u64,
13 archive_id: u16,
14}
15
16impl ArchiveWriter {
17 pub fn create(path: &Path, archive_id: u16) -> Result<Self> {
19 debug!("Creating new archive: {:?}", path);
20
21 let file = OpenOptions::new()
22 .create(true)
23 .write(true)
24 .truncate(true)
25 .open(path)?;
26
27 Ok(Self {
28 writer: BufWriter::new(file),
29 current_offset: 0,
30 archive_id,
31 })
32 }
33
34 pub fn append(path: &Path, archive_id: u16) -> Result<Self> {
36 debug!("Opening archive for append: {:?}", path);
37
38 let file = OpenOptions::new().append(true).open(path)?;
39
40 let current_offset = file.metadata()?.len();
41
42 Ok(Self {
43 writer: BufWriter::new(file),
44 current_offset,
45 archive_id,
46 })
47 }
48
49 pub fn write(&mut self, data: &[u8]) -> Result<u64> {
51 let offset = self.current_offset;
52
53 self.writer.write_all(data)?;
54 self.current_offset += data.len() as u64;
55
56 debug!(
57 "Wrote {} bytes to archive {} at offset {:x}",
58 data.len(),
59 self.archive_id,
60 offset
61 );
62
63 Ok(offset)
64 }
65
66 pub fn write_aligned(&mut self, data: &[u8], alignment: u64) -> Result<u64> {
68 let padding_needed = if self.current_offset % alignment != 0 {
70 alignment - (self.current_offset % alignment)
71 } else {
72 0
73 };
74
75 if padding_needed > 0 {
76 let padding = vec![0u8; padding_needed as usize];
77 self.writer.write_all(&padding)?;
78 self.current_offset += padding_needed;
79 }
80
81 self.write(data)
82 }
83
84 pub fn flush(&mut self) -> Result<()> {
86 self.writer.flush()?;
87 Ok(())
88 }
89
90 pub fn current_offset(&self) -> u64 {
92 self.current_offset
93 }
94
95 pub fn archive_id(&self) -> u16 {
97 self.archive_id
98 }
99
100 pub fn seek(&mut self, pos: u64) -> Result<()> {
102 self.writer.seek(SeekFrom::Start(pos))?;
103 self.current_offset = pos;
104 Ok(())
105 }
106
107 pub fn size(&mut self) -> Result<u64> {
109 self.flush()?;
110 let metadata = self.writer.get_ref().metadata()?;
111 Ok(metadata.len())
112 }
113}