Flushes all dirty metadata to disk.
(&mut self)
| 962 | |
| 963 | /// Flushes all dirty metadata to disk. |
| 964 | pub(super) fn sync_caches(&mut self) -> io::Result<()> { |
| 965 | // Write out all dirty L2 tables. |
| 966 | for (l1_index, l2_table) in self.l2_cache.iter_mut().filter(|(_k, v)| v.dirty()) { |
| 967 | let addr = self.l1_table[*l1_index]; |
| 968 | if addr != 0 { |
| 969 | self.raw_file |
| 970 | .write_pointer_table_direct(addr, l2_table.iter())?; |
| 971 | } else { |
| 972 | self.set_corrupt_bit_best_effort(); |
| 973 | return Err(io::Error::from_raw_os_error(EINVAL)); |
| 974 | } |
| 975 | l2_table.mark_clean(); |
| 976 | } |
| 977 | // Write the modified refcount blocks. |
| 978 | self.refcounts.flush_blocks(&mut self.raw_file)?; |
| 979 | // Sync metadata and data clusters. |
| 980 | self.raw_file.file_mut().sync_all()?; |
| 981 | |
| 982 | // Push L1 table and refcount table last. |
| 983 | let mut sync_required = if self.l1_table.dirty() { |
| 984 | let refcounts = &mut self.refcounts; |
| 985 | self.raw_file.write_pointer_table( |
| 986 | self.header.l1_table_offset, |
| 987 | self.l1_table.iter(), |
| 988 | |raw_file, l2_addr| { |
| 989 | if l2_addr == 0 { |
| 990 | Ok(0) |
| 991 | } else { |
| 992 | let refcount = refcounts |
| 993 | .get_cluster_refcount(raw_file, l2_addr) |
| 994 | .map_err(|e| io::Error::other(super::Error::GettingRefcount(e)))?; |
| 995 | Ok(l1_entry_make(l2_addr, refcount == 1)) |
| 996 | } |
| 997 | }, |
| 998 | )?; |
| 999 | self.l1_table.mark_clean(); |
| 1000 | true |
| 1001 | } else { |
| 1002 | false |
| 1003 | }; |
| 1004 | sync_required |= self.refcounts.flush_table(&mut self.raw_file)?; |
| 1005 | if sync_required { |
| 1006 | self.raw_file.file_mut().sync_data()?; |
| 1007 | } |
| 1008 | |
| 1009 | Ok(()) |
| 1010 | } |
| 1011 | |
| 1012 | /// Decompresses a compressed cluster, returning the raw decompressed bytes. |
| 1013 | fn decompress_l2_cluster(&mut self, l2_entry: u64) -> io::Result<Vec<u8>> { |
no test coverage detected