Skip to content

Commit

Permalink
firmware.patch handles FAT resources
Browse files Browse the repository at this point in the history
With the following patch fwup-home/fwup#202 ,
fwup is able to apply delta updates on FAT resources.

This patch update firmware.patch mix task to create firmware patches
including FAT resources delta updates.
  • Loading branch information
Jean Parpaillon authored and johngiffin committed Mar 27, 2024
1 parent f7887a6 commit 7524603
Showing 1 changed file with 79 additions and 23 deletions.
102 changes: 79 additions & 23 deletions lib/mix/tasks/firmware.patch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Mix.Tasks.Firmware.Patch do
Generate a firmware patch from a source and target firmware and output a new
firmware file with the patch contents. The source firmware file
This requires fwup >= 1.6.0
This requires fwup >= 1.10.0
## Command line options
Expand All @@ -21,7 +21,7 @@ defmodule Mix.Tasks.Firmware.Patch do
alias Mix.Nerves.Preflight
alias Nerves.Utils.Shell

@fwup_semver "~> 1.6 or ~> 1.6.0-dev"
@fwup_semver ">= 1.10.0"

@switches [source: :string, target: :string, output: :string]

Expand Down Expand Up @@ -56,27 +56,7 @@ defmodule Mix.Tasks.Firmware.Patch do

target_stats = File.stat!(target)

source_work_dir = Path.join(work_dir, "source")
target_work_dir = Path.join(work_dir, "target")
output_work_dir = Path.join(work_dir, "output")

File.mkdir_p!(source_work_dir)
File.mkdir_p!(target_work_dir)
File.mkdir_p!(Path.join(output_work_dir, "data"))

{_, 0} = shell("unzip", ["-qq", source, "-d", source_work_dir])
{_, 0} = shell("unzip", ["-qq", target, "-d", target_work_dir])

source_rootfs = Path.join([source_work_dir, "data", "rootfs.img"])
target_rootfs = Path.join([target_work_dir, "data", "rootfs.img"])
out_rootfs = Path.join([output_work_dir, "data", "rootfs.img"])

{_, 0} = shell("xdelta3", ["-A", "-S", "-f", "-s", source_rootfs, target_rootfs, out_rootfs])

File.mkdir_p!(Path.dirname(output))
File.cp!(target, output)

{_, 0} = shell("zip", ["-qq", output, "data/rootfs.img"], cd: output_work_dir)
_ = create(source, target, output, work_dir)

output_stats = File.stat!(output)

Expand Down Expand Up @@ -117,4 +97,80 @@ defmodule Mix.Tasks.Firmware.Patch do
Mix.Tasks.Firmware.run(["--output", out_fw])
out_fw
end

defp create(source_path, target_path, output_path, work_dir) do
source_work_dir = Path.join(work_dir, "source")
target_work_dir = Path.join(work_dir, "target")
output_work_dir = Path.join(work_dir, "output")

_ = File.mkdir_p(source_work_dir)
_ = File.mkdir_p(target_work_dir)
_ = File.mkdir_p(output_work_dir)

{_, 0} = shell("unzip", ["-qq", source_path, "-d", source_work_dir])
{_, 0} = shell("unzip", ["-qq", target_path, "-d", target_work_dir])

for path <- Path.wildcard(target_work_dir <> "/**") do
path = Regex.replace(~r/^#{target_work_dir}\//, path, "")

unless File.dir?(Path.join(target_work_dir, path)) do
:ok = handle_content(path, source_work_dir, target_work_dir, output_work_dir)
end
end

# firmware archive files order matters:
# 1. meta.conf.ed25519 (optional)
# 2. meta.conf
# 3. other...
[
"meta.conf.*",
"meta.conf",
"data"
]
|> Enum.each(&add_to_zip(&1, output_work_dir, output_path))

output_path
end

defp handle_content("meta." <> _ = path, _source_dir, target_dir, out_dir) do
do_copy(Path.join(target_dir, path), Path.join(out_dir, path))
end

defp handle_content(path, source_dir, target_dir, out_dir) do
do_delta(Path.join(source_dir, path), Path.join(target_dir, path), Path.join(out_dir, path))
end

defp do_copy(source, target) do
target |> Path.dirname() |> File.mkdir_p!()
File.cp(source, target)
end

defp do_delta(source, target, out) do
out |> Path.dirname() |> File.mkdir_p!()

case shell("xdelta3", ["-A", "-S", "-f", "-s", source, target, out]) do
{_, 0} -> :ok
{_, code} -> {:error, code}
end
end

defp add_to_zip(glob, workdir, output) do
workdir
|> Path.join(glob)
|> Path.wildcard()
|> case do
[] ->
:ok

paths ->
{_, 0} =
System.cmd(
"zip",
["-r", "-qq", output | Enum.map(paths, &Path.relative_to(&1, workdir))],
cd: workdir
)

:ok
end
end
end

0 comments on commit 7524603

Please sign in to comment.