summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--qcow/src/qcow.rs27
1 files changed, 26 insertions, 1 deletions
diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs
index 640f469..6373d01 100644
--- a/qcow/src/qcow.rs
+++ b/qcow/src/qcow.rs
@@ -388,7 +388,7 @@ impl QcowFile {
 
         let l2_entries = cluster_size / size_of::<u64>() as u64;
 
-        let qcow = QcowFile {
+        let mut qcow = QcowFile {
             raw_file,
             header,
             l1_table,
@@ -410,6 +410,8 @@ impl QcowFile {
             .checked_add(u64::from(qcow.header.refcount_table_clusters) * cluster_size)
             .ok_or(Error::InvalidRefcountTableOffset)?;
 
+        qcow.find_avail_clusters()?;
+
         Ok(qcow)
     }
 
@@ -517,6 +519,29 @@ impl QcowFile {
         Ok(None)
     }
 
+    fn find_avail_clusters(&mut self) -> Result<()> {
+        let cluster_size = self.raw_file.cluster_size();
+
+        let file_size = self
+            .raw_file
+            .file_mut()
+            .metadata()
+            .map_err(Error::GettingFileSize)?
+            .len();
+
+        for i in (0..file_size).step_by(cluster_size as usize) {
+            let refcount = self
+                .refcounts
+                .get_cluster_refcount(&mut self.raw_file, i)
+                .map_err(Error::GettingRefcount)?;
+            if refcount == 0 {
+                self.avail_clusters.push(i);
+            }
+        }
+
+        Ok(())
+    }
+
     /// Rebuild the reference count tables.
     fn rebuild_refcounts(raw_file: &mut QcowRawFile, header: QcowHeader) -> Result<()> {
         fn add_ref(refcounts: &mut [u16], cluster_size: u64, cluster_address: u64) -> Result<()> {