|
| 1 | +defmodule Bakeware.FileTree do |
| 2 | + alias Bakeware.Assembler |
| 3 | + |
| 4 | + @moduledoc """ |
| 5 | + Builds a FileTree header for recreating decompressed files |
| 6 | +
|
| 7 | + Header structure: |
| 8 | +
|
| 9 | + `<<bw_ft_magic, bw_ft_version, header_length, file_tree_items>>` |
| 10 | +
|
| 11 | + where `file_tree_items` is a repeating structure of: |
| 12 | +
|
| 13 | + `<<file_type, size, path_len, relative_path::size(path_len)-unit(8)>>` |
| 14 | + """ |
| 15 | + |
| 16 | + # ?F + ?T |
| 17 | + @bw_ft_magic 154 |
| 18 | + @bw_ft_version 1 |
| 19 | + |
| 20 | + def build(%Assembler{} = assembler) do |
| 21 | + find_files(assembler.rel_path, assembler.rel_path) |
| 22 | + |> finalize_header() |
| 23 | + |
| 24 | + # TODO: Do something with this |
| 25 | + |
| 26 | + assembler |
| 27 | + end |
| 28 | + |
| 29 | + def find_files(path, absolute, acc \\ <<>>) do |
| 30 | + for fp <- File.ls!(path), file_or_dir = Path.join(path, fp), into: acc do |
| 31 | + if File.dir?(file_or_dir) do |
| 32 | + acc = acc <> build_stat(file_or_dir, absolute) |
| 33 | + find_files(file_or_dir, absolute, acc) |
| 34 | + else |
| 35 | + build_stat(file_or_dir, absolute) |
| 36 | + end |
| 37 | + end |
| 38 | + end |
| 39 | + |
| 40 | + def finalize_header(header) do |
| 41 | + len = byte_size(header) |
| 42 | + <<@bw_ft_magic, @bw_ft_version, len, header::binary>> |
| 43 | + end |
| 44 | + |
| 45 | + defp build_stat(path, absolute) do |
| 46 | + relative = Path.relative_to(path, absolute) |
| 47 | + stat = File.lstat!(path) |
| 48 | + path_len = byte_size(path) |
| 49 | + <<type_val(stat.type), stat.size, path_len, relative::binary>> |
| 50 | + end |
| 51 | + |
| 52 | + defp type_val(type) do |
| 53 | + case type do |
| 54 | + :device -> 1 |
| 55 | + :directory -> 2 |
| 56 | + :regular -> 3 |
| 57 | + :symlink -> 4 |
| 58 | + :other -> 5 |
| 59 | + # unknown |
| 60 | + _ -> 0 |
| 61 | + end |
| 62 | + end |
| 63 | +end |
0 commit comments