• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! `append_squashfs_overlay` generates a new squashfs image(dest) which contains an overlay image(overlay) on an squashfs image(src).
18 //! The tool ignores the existing overlay image in src, that is, the overlay image could be replaced with a new overlay image.
19 use std::fs::File;
20 use std::io::{copy, Error, ErrorKind, Read, Result, Seek, SeekFrom};
21 use std::path::Path;
22 
23 use clap::{App, Arg};
24 
25 // https://dr-emann.github.io/squashfs/squashfs.html
26 const BYTES_USED_FIELD_POS: u64 = (32 * 5 + 16 * 6 + 64) / 8;
27 const SQUASHFS_MAGIC: u32 = 0x73717368;
28 
29 // https://git.openwrt.org/?p=project/fstools.git;a=blob;f=libfstools/rootdisk.c;h=9f2317f14e8d8f12c71b30944138d7a6c877b406;hb=refs/heads/master#l125
30 // 64kb alignment
31 const ROOTDEV_OVERLAY_ALIGN: u64 = 64 * 1024;
32 
align_size(size: u64, alignment: u64) -> u6433 fn align_size(size: u64, alignment: u64) -> u64 {
34     assert!(
35         alignment > 0 && (alignment & (alignment - 1) == 0),
36         "alignment should be greater than 0 and a power of 2."
37     );
38     (size + (alignment - 1)) & !(alignment - 1)
39 }
40 
merge_fs(src: &Path, overlay: &Path, dest: &Path, overwrite: bool) -> Result<()>41 fn merge_fs(src: &Path, overlay: &Path, dest: &Path, overwrite: bool) -> Result<()> {
42     if dest.exists() && !overwrite {
43         return Err(Error::new(
44             ErrorKind::AlreadyExists,
45             "The destination file already exists, add -w option to overwrite.",
46         ));
47     }
48     let mut buffer = [0; 4];
49 
50     let mut src = File::open(src)?;
51 
52     src.read_exact(&mut buffer)?;
53     let magic = u32::from_le_bytes(buffer);
54     if magic != SQUASHFS_MAGIC {
55         return Err(Error::new(ErrorKind::InvalidData, "The source image isn't a squashfs image."));
56     }
57     src.seek(SeekFrom::Start(BYTES_USED_FIELD_POS))?;
58     let mut buffer = [0; 8];
59     src.read_exact(&mut buffer)?;
60 
61     // https://git.openwrt.org/?p=project/fstools.git;a=blob;f=libfstools/rootdisk.c;h=9f2317f14e8d8f12c71b30944138d7a6c877b406;hb=refs/heads/master#l125
62     // use little endian
63     let bytes_used = u64::from_le_bytes(buffer);
64     let mut dest = File::create(dest)?;
65     let mut overlay = File::open(overlay)?;
66 
67     src.seek(SeekFrom::Start(0))?;
68     let mut src_handle = src.take(align_size(bytes_used, ROOTDEV_OVERLAY_ALIGN));
69     copy(&mut src_handle, &mut dest)?;
70     copy(&mut overlay, &mut dest)?;
71     Ok(())
72 }
73 
main() -> Result<()>74 fn main() -> Result<()> {
75     let matches = App::new("append_squashfs_overlay")
76         .arg(Arg::with_name("src").required(true))
77         .arg(Arg::with_name("overlay").required(true))
78         .arg(Arg::with_name("dest").required(true))
79         .arg(
80             Arg::with_name("overwrite")
81                 .short("w")
82                 .required(false)
83                 .takes_value(false)
84                 .help("whether the tool overwrite dest or not"),
85         )
86         .get_matches();
87 
88     let src = matches.value_of("src").unwrap().as_ref();
89     let overlay = matches.value_of("overlay").unwrap().as_ref();
90     let dest = matches.value_of("dest").unwrap().as_ref();
91     let overwrite = matches.is_present("overwrite");
92 
93     merge_fs(src, overlay, dest, overwrite)?;
94     Ok(())
95 }
96