blob: 281aef875e40afac478dc08bd6da31e0d846a072 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! `append_squashfs_overlay` generates a new squashfs image(dest) which contains an overlay image(overlay) on an squashfs image(src).
//! The tool ignores the existing overlay image in src, that is, the overlay image could be replaced with a new overlay image.
use std::fs::File;
use std::io::{copy, Error, ErrorKind, Read, Result, Seek, SeekFrom};
use std::path::Path;
use clap::{App, Arg};
// https://dr-emann.github.io/squashfs/squashfs.html
const BYTES_USED_FIELD_POS: u64 = (32 * 5 + 16 * 6 + 64) / 8;
const SQUASHFS_MAGIC: u32 = 0x73717368;
// https://git.openwrt.org/?p=project/fstools.git;a=blob;f=libfstools/rootdisk.c;h=9f2317f14e8d8f12c71b30944138d7a6c877b406;hb=refs/heads/master#l125
// 64kb alignment
const ROOTDEV_OVERLAY_ALIGN: u64 = 64 * 1024;
fn align_size(size: u64, alignment: u64) -> u64 {
assert!(
alignment > 0 && (alignment & (alignment - 1) == 0),
"alignment should be greater than 0 and a power of 2."
);
(size + (alignment - 1)) & !(alignment - 1)
}
fn merge_fs(src: &Path, overlay: &Path, dest: &Path, overwrite: bool) -> Result<()> {
if dest.exists() && !overwrite {
return Err(Error::new(
ErrorKind::AlreadyExists,
"The destination file already exists, add -w option to overwrite.",
));
}
let mut buffer = [0; 4];
let mut src = File::open(src)?;
src.read_exact(&mut buffer)?;
let magic = u32::from_le_bytes(buffer);
if magic != SQUASHFS_MAGIC {
return Err(Error::new(ErrorKind::InvalidData, "The source image isn't a squashfs image."));
}
src.seek(SeekFrom::Start(BYTES_USED_FIELD_POS))?;
let mut buffer = [0; 8];
src.read_exact(&mut buffer)?;
// https://git.openwrt.org/?p=project/fstools.git;a=blob;f=libfstools/rootdisk.c;h=9f2317f14e8d8f12c71b30944138d7a6c877b406;hb=refs/heads/master#l125
// use little endian
let bytes_used = u64::from_le_bytes(buffer);
let mut dest = File::create(dest)?;
let mut overlay = File::open(overlay)?;
src.seek(SeekFrom::Start(0))?;
let mut src_handle = src.take(align_size(bytes_used, ROOTDEV_OVERLAY_ALIGN));
copy(&mut src_handle, &mut dest)?;
copy(&mut overlay, &mut dest)?;
Ok(())
}
fn main() -> Result<()> {
let matches = App::new("append_squashfs_overlay")
.arg(Arg::with_name("src").required(true))
.arg(Arg::with_name("overlay").required(true))
.arg(Arg::with_name("dest").required(true))
.arg(
Arg::with_name("overwrite")
.short("w")
.required(false)
.takes_value(false)
.help("whether the tool overwrite dest or not"),
)
.get_matches();
let src = matches.value_of("src").unwrap().as_ref();
let overlay = matches.value_of("overlay").unwrap().as_ref();
let dest = matches.value_of("dest").unwrap().as_ref();
let overwrite = matches.is_present("overwrite");
merge_fs(src, overlay, dest, overwrite)?;
Ok(())
}