• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2025 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Utilities for working with directories for snapshots.
6 
7 use std::collections::BTreeMap as Map;
8 use std::path::Path;
9 use std::path::PathBuf;
10 
11 use anyhow::Context;
12 use serde::Deserialize;
13 use serde::Serialize;
14 
get_files_recursively(directory: &Path, paths: &mut Vec<PathBuf>) -> anyhow::Result<()>15 fn get_files_recursively(directory: &Path, paths: &mut Vec<PathBuf>) -> anyhow::Result<()> {
16     if directory.is_dir() {
17         for entry in std::fs::read_dir(directory)? {
18             let entry = entry?;
19             let entry_path = entry.path();
20             if entry_path.is_dir() {
21                 get_files_recursively(&entry_path, paths)?;
22             } else {
23                 paths.push(entry_path.to_path_buf());
24             }
25         }
26     }
27     Ok(())
28 }
29 
get_files_under(directory: &Path) -> anyhow::Result<Vec<PathBuf>>30 fn get_files_under(directory: &Path) -> anyhow::Result<Vec<PathBuf>> {
31     let mut paths = Vec::new();
32     get_files_recursively(directory, &mut paths)?;
33     Ok(paths)
34 }
35 
36 // TODO: use an actual archive/zip when a common crate is available in
37 // both Android and Chrome.
38 #[derive(Serialize, Deserialize)]
39 pub struct DirectorySnapshot {
40     files: Map<PathBuf, Vec<u8>>,
41 }
42 
pack_directory_to_snapshot(directory: &Path) -> anyhow::Result<DirectorySnapshot>43 pub fn pack_directory_to_snapshot(directory: &Path) -> anyhow::Result<DirectorySnapshot> {
44     let directory_files = get_files_under(directory).with_context(|| {
45         format!(
46             "failed to list snapshot files under {}",
47             directory.display()
48         )
49     })?;
50 
51     let mut snapshot = DirectorySnapshot { files: Map::new() };
52 
53     for path in directory_files.into_iter() {
54         let contents: Vec<u8> = std::fs::read(&path)
55             .with_context(|| format!("failed to read snapshot file {}", path.display()))?;
56 
57         let relative_path = path
58             .strip_prefix(directory)
59             .with_context(|| {
60                 format!(
61                     "failed to strip {} from {}",
62                     directory.display(),
63                     path.display()
64                 )
65             })?
66             .to_path_buf();
67 
68         snapshot.files.insert(relative_path, contents);
69     }
70 
71     Ok(snapshot)
72 }
73 
unpack_snapshot_to_directory( directory: &Path, snapshot: DirectorySnapshot, ) -> anyhow::Result<()>74 pub fn unpack_snapshot_to_directory(
75     directory: &Path,
76     snapshot: DirectorySnapshot,
77 ) -> anyhow::Result<()> {
78     for (path, contents) in snapshot.files.into_iter() {
79         let path = directory.join(path);
80         let path_directory = path
81             .parent()
82             .with_context(|| format!("failed to get parent directory for {}", path.display()))?;
83         std::fs::create_dir_all(path_directory)
84             .with_context(|| format!("failed to create directories for {}", path.display()))?;
85         std::fs::write(&path, contents)
86             .with_context(|| format!("failed to unpack snapshot to {}", path.display()))?;
87     }
88 
89     Ok(())
90 }
91