Skip to main content

src/packkit@cpio.erl

-module(packkit@cpio).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/cpio.gleam").
-export([format/0, new/0, decode_with_limits/2, decode/1, encode/1]).
-export_type([parsed_header/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " CPIO \"newc\" (SVR4) archive encoder and decoder.\n"
    "\n"
    " The newc format uses fixed 110-byte ASCII hex headers and pads\n"
    " names and bodies to a 4-byte alignment.  This module implements\n"
    " regular files, directories, and symbolic links.  Hard links are\n"
    " rejected because newc represents them through shared inode numbers\n"
    " rather than a distinct typeflag.\n"
).

-type parsed_header() :: {parsed_header,
        integer(),
        integer(),
        integer(),
        integer(),
        integer(),
        integer()}.

-file("src/packkit/cpio.gleam", 38).
?DOC(" CPIO newc archive format marker.\n").
-spec format() -> packkit@archive:archive_format().
format() ->
    packkit@archive:cpio_newc().

-file("src/packkit/cpio.gleam", 43).
?DOC(" Create an empty CPIO newc archive value.\n").
-spec new() -> packkit@archive:archive().
new() ->
    packkit@archive:new(format()).

-file("src/packkit/cpio.gleam", 61).
-spec reject_comment(packkit@archive:archive()) -> {ok, nil} |
    {error, packkit@error:archive_error()}.
reject_comment(Archive_value) ->
    case packkit@archive:comment(Archive_value) of
        none ->
            {ok, nil};

        {some, _} ->
            {error, {archive_comment_unsupported, <<"cpio-newc"/utf8>>}}
    end.

-file("src/packkit/cpio.gleam", 142).
-spec check_member_limit(integer(), packkit@limit:limits()) -> {ok, nil} |
    {error, packkit@error:archive_error()}.
check_member_limit(Count, Limits) ->
    case Count > packkit@limit:max_members(Limits) of
        true ->
            {error, {archive_limit_exceeded, <<"max_members"/utf8>>, Count}};

        false ->
            {ok, nil}
    end.

-file("src/packkit/cpio.gleam", 246).
-spec entry_error_to_archive_error(packkit@entry:entry_error(), binary()) -> packkit@error:archive_error().
entry_error_to_archive_error(Err, Path) ->
    case Err of
        empty_path ->
            {archive_entry_rejected, Path, <<"empty path"/utf8>>};

        {absolute_path, _} ->
            {archive_entry_rejected, Path, <<"absolute path"/utf8>>};

        {path_traversal, _} ->
            {archive_entry_rejected, Path, <<"path traversal"/utf8>>};

        {windows_path, _} ->
            {archive_entry_rejected, Path, <<"windows path"/utf8>>};

        {empty_segment, _} ->
            {archive_entry_rejected, Path, <<"empty segment"/utf8>>};

        {dot_segment, _} ->
            {archive_entry_rejected, Path, <<"dot segment"/utf8>>};

        {contains_nul, _} ->
            {archive_entry_rejected, Path, <<"nul byte"/utf8>>}
    end.

-file("src/packkit/cpio.gleam", 413).
-spec hex_digits_loop(integer(), integer(), bitstring()) -> bitstring().
hex_digits_loop(Value, Remaining, Acc) ->
    case Remaining of
        0 ->
            Acc;

        _ ->
            Digit = erlang:'band'(Value, 15),
            Next = erlang:'bsr'(Value, 4),
            Ch = case Digit < 10 of
                true ->
                    16#30 + Digit;

                false ->
                    16#61 + (Digit - 10)
            end,
            hex_digits_loop(Next, Remaining - 1, <<Ch, Acc/bitstring>>)
    end.

-file("src/packkit/cpio.gleam", 409).
-spec hex_digits(integer(), integer()) -> bitstring().
hex_digits(Value, Width) ->
    hex_digits_loop(Value, Width, <<>>).

-file("src/packkit/cpio.gleam", 405).
-spec hex_field(integer()) -> bitstring().
hex_field(Value) ->
    hex_digits(Value, 8).

-file("src/packkit/cpio.gleam", 444).
-spec byte_repeat_loop(integer(), integer(), bitstring()) -> bitstring().
byte_repeat_loop(Byte, Count, Acc) ->
    case Count of
        0 ->
            Acc;

        _ ->
            byte_repeat_loop(Byte, Count - 1, <<Acc/bitstring, Byte>>)
    end.

-file("src/packkit/cpio.gleam", 440).
-spec byte_repeat(integer(), integer()) -> bitstring().
byte_repeat(Byte, Count) ->
    byte_repeat_loop(Byte, Count, <<>>).

-file("src/packkit/cpio.gleam", 451).
-spec slice_or_error(bitstring(), integer(), integer()) -> {ok, bitstring()} |
    {error, packkit@error:archive_error()}.
slice_or_error(Block, Offset, Width) ->
    case gleam_stdlib:bit_array_slice(Block, Offset, Width) of
        {ok, Value} ->
            {ok, Value};

        {error, _} ->
            {error, {archive_invalid, <<"cpio field out of bounds"/utf8>>}}
    end.

-file("src/packkit/cpio.gleam", 484).
-spec hex_value(integer()) -> {ok, integer()} | {error, nil}.
hex_value(Byte) ->
    case Byte of
        N when (N >= 16#30) andalso (N =< 16#39) ->
            {ok, N - 16#30};

        N@1 when (N@1 >= 16#41) andalso (N@1 =< 16#46) ->
            {ok, (N@1 - 16#41) + 10};

        N@2 when (N@2 >= 16#61) andalso (N@2 =< 16#66) ->
            {ok, (N@2 - 16#61) + 10};

        _ ->
            {error, nil}
    end.

-file("src/packkit/cpio.gleam", 470).
-spec parse_hex(bitstring(), integer()) -> {ok, integer()} |
    {error, packkit@error:archive_error()}.
parse_hex(Bytes, Acc) ->
    case Bytes of
        <<>> ->
            {ok, Acc};

        <<B, Rest/binary>> ->
            case hex_value(B) of
                {ok, Value} ->
                    parse_hex(Rest, (Acc * 16) + Value);

                {error, _} ->
                    {error,
                        {archive_invalid,
                            <<"invalid hex byte in cpio header"/utf8>>}}
            end;

        _ ->
            {ok, Acc}
    end.

-file("src/packkit/cpio.gleam", 462).
-spec read_hex_field(bitstring(), integer()) -> {ok, integer()} |
    {error, packkit@error:archive_error()}.
read_hex_field(Block, Offset) ->
    gleam@result:'try'(
        slice_or_error(Block, Offset, 8),
        fun(Slice) -> parse_hex(Slice, 0) end
    ).

-file("src/packkit/cpio.gleam", 493).
-spec bytes_to_string(bitstring()) -> {ok, binary()} |
    {error, packkit@error:archive_error()}.
bytes_to_string(Bytes) ->
    case gleam@bit_array:to_string(Bytes) of
        {ok, Value} ->
            {ok, Value};

        {error, _} ->
            {error,
                {archive_invalid, <<"non-UTF-8 string in cpio header"/utf8>>}}
    end.

-file("src/packkit/cpio.gleam", 506).
-spec strip_trailing_nul_loop(bitstring(), integer()) -> bitstring().
strip_trailing_nul_loop(Bytes, Size) ->
    case Size of
        0 ->
            <<>>;

        _ ->
            case gleam_stdlib:bit_array_slice(Bytes, Size - 1, 1) of
                {ok, <<0>>} ->
                    strip_trailing_nul_loop(Bytes, Size - 1);

                _ ->
                    Slice@1 = case gleam_stdlib:bit_array_slice(Bytes, 0, Size) of
                        {ok, Slice} -> Slice;
                        _assert_fail ->
                            erlang:error(#{gleam_error => let_assert,
                                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                        file => <<?FILEPATH/utf8>>,
                                        module => <<"packkit/cpio"/utf8>>,
                                        function => <<"strip_trailing_nul_loop"/utf8>>,
                                        line => 513,
                                        value => _assert_fail,
                                        start => 14304,
                                        'end' => 14358,
                                        pattern_start => 14315,
                                        pattern_end => 14324})
                    end,
                    Slice@1
            end
    end.

-file("src/packkit/cpio.gleam", 501).
-spec strip_trailing_nul(bitstring()) -> bitstring().
strip_trailing_nul(Bytes) ->
    Size = erlang:byte_size(Bytes),
    strip_trailing_nul_loop(Bytes, Size).

-file("src/packkit/cpio.gleam", 377).
-spec build_header(
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer(),
    integer()
) -> bitstring().
build_header(Ino, Mode, Uid, Gid, Nlink, Mtime, Filesize, Namesize) ->
    gleam_stdlib:bit_array_concat(
        [gleam_stdlib:identity(<<"070701"/utf8>>),
            hex_field(Ino),
            hex_field(Mode),
            hex_field(Uid),
            hex_field(Gid),
            hex_field(Nlink),
            hex_field(Mtime),
            hex_field(Filesize),
            hex_field(0),
            hex_field(0),
            hex_field(0),
            hex_field(0),
            hex_field(Namesize),
            hex_field(0)]
    ).

-file("src/packkit/cpio.gleam", 164).
-spec parse_header(bitstring()) -> {ok, parsed_header()} |
    {error, packkit@error:archive_error()}.
parse_header(Block) ->
    gleam@result:'try'(
        slice_or_error(Block, 0, 6),
        fun(Magic_bits) ->
            gleam@result:'try'(
                bytes_to_string(Magic_bits),
                fun(Magic) ->
                    gleam@bool:guard(
                        (Magic /= <<"070701"/utf8>>) andalso (Magic /= <<"070702"/utf8>>),
                        {error,
                            {archive_invalid,
                                <<"not a newc/crc cpio magic"/utf8>>}},
                        fun() ->
                            gleam@result:'try'(
                                read_hex_field(Block, 14),
                                fun(Mode) ->
                                    gleam@result:'try'(
                                        read_hex_field(Block, 22),
                                        fun(Uid) ->
                                            gleam@result:'try'(
                                                read_hex_field(Block, 30),
                                                fun(Gid) ->
                                                    gleam@result:'try'(
                                                        read_hex_field(
                                                            Block,
                                                            46
                                                        ),
                                                        fun(Mtime) ->
                                                            gleam@result:'try'(
                                                                read_hex_field(
                                                                    Block,
                                                                    54
                                                                ),
                                                                fun(Filesize) ->
                                                                    gleam@result:'try'(
                                                                        read_hex_field(
                                                                            Block,
                                                                            94
                                                                        ),
                                                                        fun(
                                                                            Namesize
                                                                        ) ->
                                                                            {ok,
                                                                                {parsed_header,
                                                                                    Mode,
                                                                                    Uid,
                                                                                    Gid,
                                                                                    Mtime,
                                                                                    Filesize,
                                                                                    Namesize}}
                                                                        end
                                                                    )
                                                                end
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/packkit/cpio.gleam", 433).
-spec pad_to_align(integer()) -> integer().
pad_to_align(Position) ->
    case case 4 of
        0 -> 0;
        Gleam@denominator -> Position rem Gleam@denominator
    end of
        0 ->
            Position;

        Rem ->
            Position + (4 - Rem)
    end.

-file("src/packkit/cpio.gleam", 428).
-spec align_padding(integer()) -> bitstring().
align_padding(Position) ->
    Aligned = pad_to_align(Position),
    byte_repeat(0, Aligned - Position).

-file("src/packkit/cpio.gleam", 355).
-spec trailer_record() -> bitstring().
trailer_record() ->
    Name_bytes = gleam_stdlib:identity(<<"TRAILER!!!"/utf8>>),
    Name_size = erlang:byte_size(Name_bytes) + 1,
    Header = build_header(0, 0, 0, 0, 1, 0, 0, Name_size),
    gleam_stdlib:bit_array_concat(
        [Header, Name_bytes, <<0>>, align_padding(110 + Name_size)]
    ).

-file("src/packkit/cpio.gleam", 194).
-spec header_to_entry(
    parsed_header(),
    binary(),
    bitstring(),
    packkit@limit:limits()
) -> {ok, packkit@entry:entry()} | {error, packkit@error:archive_error()}.
header_to_entry(Header, Name, Body, Limits) ->
    gleam@bool:guard(
        erlang:byte_size(Name) > packkit@limit:max_entry_name_bytes(Limits),
        {error,
            {archive_limit_exceeded,
                <<"max_entry_name_bytes"/utf8>>,
                erlang:byte_size(Name)}},
        fun() ->
            File_type = erlang:'band'(erlang:element(2, Header), 8#170000),
            Perm = erlang:'band'(erlang:element(2, Header), 8#7777),
            gleam@result:'try'(case File_type of
                    Type_ when Type_ =:= 8#100000 ->
                        _pipe = packkit@entry:file_checked(Name, Body),
                        gleam@result:map_error(
                            _pipe,
                            fun(_capture) ->
                                entry_error_to_archive_error(_capture, Name)
                            end
                        );

                    Type_@1 when Type_@1 =:= 8#040000 ->
                        _pipe@1 = packkit@entry:directory_checked(Name),
                        gleam@result:map_error(
                            _pipe@1,
                            fun(_capture@1) ->
                                entry_error_to_archive_error(_capture@1, Name)
                            end
                        );

                    Type_@2 when Type_@2 =:= 8#120000 ->
                        gleam@result:'try'(
                            bytes_to_string(Body),
                            fun(Target) ->
                                _pipe@2 = packkit@entry:symlink_checked(
                                    Name,
                                    Target
                                ),
                                gleam@result:map_error(
                                    _pipe@2,
                                    fun(_capture@2) ->
                                        entry_error_to_archive_error(
                                            _capture@2,
                                            Name
                                        )
                                    end
                                )
                            end
                        );

                    Other ->
                        {error,
                            {archive_invalid,
                                <<"unsupported cpio mode "/utf8,
                                    (erlang:integer_to_binary(Other))/binary>>}}
                end, fun(Base) ->
                    Depth = packkit@entry:depth(packkit@entry:path(Base)),
                    gleam@bool:guard(
                        Depth > packkit@limit:max_entry_depth(Limits),
                        {error,
                            {archive_limit_exceeded,
                                <<"max_entry_depth"/utf8>>,
                                Depth}},
                        fun() ->
                            {ok,
                                begin
                                    _pipe@3 = Base,
                                    _pipe@4 = packkit@entry:with_mode(
                                        _pipe@3,
                                        Perm
                                    ),
                                    _pipe@5 = packkit@entry:with_owner(
                                        _pipe@4,
                                        erlang:element(3, Header),
                                        erlang:element(4, Header)
                                    ),
                                    packkit@entry:with_modified_at(
                                        _pipe@5,
                                        erlang:element(5, Header)
                                    )
                                end}
                        end
                    )
                end)
        end
    ).

-file("src/packkit/cpio.gleam", 94).
-spec decode_loop(
    bitstring(),
    list(packkit@entry:entry()),
    integer(),
    packkit@limit:limits()
) -> {ok, list(packkit@entry:entry())} | {error, packkit@error:archive_error()}.
decode_loop(Bytes, Acc, Count, Limits) ->
    gleam@bool:guard(
        erlang:byte_size(Bytes) < 110,
        {error, {archive_invalid, <<"cpio header truncated"/utf8>>}},
        fun() ->
            Header_bits@1 = case gleam_stdlib:bit_array_slice(Bytes, 0, 110) of
                {ok, Header_bits} -> Header_bits;
                _assert_fail ->
                    erlang:error(#{gleam_error => let_assert,
                                message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                file => <<?FILEPATH/utf8>>,
                                module => <<"packkit/cpio"/utf8>>,
                                function => <<"decode_loop"/utf8>>,
                                line => 105,
                                value => _assert_fail,
                                start => 2795,
                                'end' => 2862,
                                pattern_start => 2806,
                                pattern_end => 2821})
            end,
            gleam@result:'try'(
                parse_header(Header_bits@1),
                fun(Header) ->
                    Name_offset = 110,
                    Name_size = erlang:element(7, Header),
                    Name_bytes_with_nul@1 = case gleam_stdlib:bit_array_slice(
                        Bytes,
                        Name_offset,
                        Name_size
                    ) of
                        {ok, Name_bytes_with_nul} -> Name_bytes_with_nul;
                        _assert_fail@1 ->
                            erlang:error(#{gleam_error => let_assert,
                                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                        file => <<?FILEPATH/utf8>>,
                                        module => <<"packkit/cpio"/utf8>>,
                                        function => <<"decode_loop"/utf8>>,
                                        line => 110,
                                        value => _assert_fail@1,
                                        start => 2986,
                                        'end' => 3073,
                                        pattern_start => 2997,
                                        pattern_end => 3020})
                    end,
                    gleam@result:'try'(
                        bytes_to_string(
                            strip_trailing_nul(Name_bytes_with_nul@1)
                        ),
                        fun(Name) ->
                            Header_plus_name = 110 + Name_size,
                            After_name_padding = pad_to_align(Header_plus_name),
                            Body_offset = After_name_padding,
                            Body_size = erlang:element(6, Header),
                            Body_padding = pad_to_align(Body_size) - Body_size,
                            Next_offset = (Body_offset + Body_size) + Body_padding,
                            gleam@bool:guard(
                                erlang:byte_size(Bytes) < (Body_offset + Body_size),
                                {error,
                                    {archive_invalid,
                                        <<"cpio entry truncated"/utf8>>}},
                                fun() -> case Name =:= <<"TRAILER!!!"/utf8>> of
                                        true ->
                                            {ok, Acc};

                                        false ->
                                            gleam@result:'try'(
                                                check_member_limit(
                                                    Count + 1,
                                                    Limits
                                                ),
                                                fun(_) ->
                                                    Body@1 = case gleam_stdlib:bit_array_slice(
                                                        Bytes,
                                                        Body_offset,
                                                        Body_size
                                                    ) of
                                                        {ok, Body} -> Body;
                                                        _assert_fail@2 ->
                                                            erlang:error(
                                                                    #{gleam_error => let_assert,
                                                                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                                                        file => <<?FILEPATH/utf8>>,
                                                                        module => <<"packkit/cpio"/utf8>>,
                                                                        function => <<"decode_loop"/utf8>>,
                                                                        line => 132,
                                                                        value => _assert_fail@2,
                                                                        start => 3764,
                                                                        'end' => 3832,
                                                                        pattern_start => 3775,
                                                                        pattern_end => 3783}
                                                                )
                                                    end,
                                                    gleam@result:'try'(
                                                        header_to_entry(
                                                            Header,
                                                            Name,
                                                            Body@1,
                                                            Limits
                                                        ),
                                                        fun(Entry_value) ->
                                                            Advance = Next_offset,
                                                            Remaining = erlang:byte_size(
                                                                Bytes
                                                            )
                                                            - Advance,
                                                            Rest@1 = case gleam_stdlib:bit_array_slice(
                                                                Bytes,
                                                                Advance,
                                                                Remaining
                                                            ) of
                                                                {ok, Rest} -> Rest;
                                                                _assert_fail@3 ->
                                                                    erlang:error(
                                                                            #{gleam_error => let_assert,
                                                                                message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                                                                file => <<?FILEPATH/utf8>>,
                                                                                module => <<"packkit/cpio"/utf8>>,
                                                                                function => <<"decode_loop"/utf8>>,
                                                                                line => 136,
                                                                                value => _assert_fail@3,
                                                                                start => 4011,
                                                                                'end' => 4075,
                                                                                pattern_start => 4022,
                                                                                pattern_end => 4030}
                                                                        )
                                                            end,
                                                            decode_loop(
                                                                Rest@1,
                                                                [Entry_value |
                                                                    Acc],
                                                                Count + 1,
                                                                Limits
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                    end end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/packkit/cpio.gleam", 78).
?DOC(" Decode a newc byte stream using explicit limits.\n").
-spec decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
        packkit@archive:archive()} |
    {error, packkit@error:archive_error()}.
decode_with_limits(Bytes, Limits) ->
    gleam@bool:guard(
        erlang:byte_size(Bytes) > packkit@limit:max_input_bytes(Limits),
        {error,
            {archive_limit_exceeded,
                <<"max_input_bytes"/utf8>>,
                erlang:byte_size(Bytes)}},
        fun() -> _pipe = decode_loop(Bytes, [], 0, Limits),
            _pipe@1 = gleam@result:map(_pipe, fun lists:reverse/1),
            gleam@result:map(
                _pipe@1,
                fun(_capture) ->
                    packkit@archive:from_entries(format(), _capture)
                end
            ) end
    ).

-file("src/packkit/cpio.gleam", 71).
?DOC(" Decode a newc byte stream using default limits.\n").
-spec decode(bitstring()) -> {ok, packkit@archive:archive()} |
    {error, packkit@error:archive_error()}.
decode(Bytes) ->
    decode_with_limits(Bytes, packkit@limit:default()).

-file("src/packkit/cpio.gleam", 343).
-spec check_hex_field(integer(), binary()) -> {ok, nil} |
    {error, packkit@error:archive_error()}.
check_hex_field(Value, Field) ->
    case (Value < 0) orelse (Value > 16#FFFFFFFF) of
        true ->
            {error,
                {archive_field_overflow,
                    <<"cpio-newc "/utf8, Field/binary>>,
                    Value,
                    16#FFFFFFFF}};

        false ->
            {ok, nil}
    end.

-file("src/packkit/cpio.gleam", 268).
-spec encode_entry(packkit@entry:entry()) -> {ok, bitstring()} |
    {error, packkit@error:archive_error()}.
encode_entry(Value) ->
    Kind = packkit@entry:kind(Value),
    gleam@bool:guard(
        Kind =:= hardlink,
        {error,
            {archive_entry_rejected,
                packkit@entry:to_string(packkit@entry:path(Value)),
                <<"cpio newc cannot represent hard links"/utf8>>}},
        fun() ->
            Path = packkit@entry:to_string(packkit@entry:path(Value)),
            Name_bytes = gleam_stdlib:identity(Path),
            Name_size = erlang:byte_size(Name_bytes) + 1,
            Metadata = packkit@entry:metadata(Value),
            {Mode_bits, Body} = case Kind of
                file ->
                    {8#100000, packkit@entry:body(Value)};

                directory ->
                    {8#040000, <<>>};

                symlink ->
                    Target = case packkit@entry:link_target(Value) of
                        {some, T} ->
                            T;

                        none ->
                            <<""/utf8>>
                    end,
                    {8#120000, gleam_stdlib:identity(Target)};

                hardlink ->
                    {8#100000, packkit@entry:body(Value)}
            end,
            Mode = erlang:'bor'(Mode_bits, packkit@entry:mode(Metadata)),
            Body_size = erlang:byte_size(Body),
            Uid = packkit@entry:user_id(Metadata),
            Gid = packkit@entry:group_id(Metadata),
            Mtime = packkit@entry:modified_at_unix(Metadata),
            gleam@result:'try'(
                check_hex_field(Mode, <<"mode"/utf8>>),
                fun(_) ->
                    gleam@result:'try'(
                        check_hex_field(Uid, <<"uid"/utf8>>),
                        fun(_) ->
                            gleam@result:'try'(
                                check_hex_field(Gid, <<"gid"/utf8>>),
                                fun(_) ->
                                    gleam@result:'try'(
                                        check_hex_field(Mtime, <<"mtime"/utf8>>),
                                        fun(_) ->
                                            gleam@result:'try'(
                                                check_hex_field(
                                                    Body_size,
                                                    <<"filesize"/utf8>>
                                                ),
                                                fun(_) ->
                                                    gleam@result:'try'(
                                                        check_hex_field(
                                                            Name_size,
                                                            <<"namesize"/utf8>>
                                                        ),
                                                        fun(_) ->
                                                            Header = build_header(
                                                                0,
                                                                Mode,
                                                                Uid,
                                                                Gid,
                                                                case Kind =:= directory of
                                                                    true ->
                                                                        2;

                                                                    false ->
                                                                        1
                                                                end,
                                                                Mtime,
                                                                Body_size,
                                                                Name_size
                                                            ),
                                                            Header_with_name = gleam_stdlib:bit_array_concat(
                                                                [Header,
                                                                    Name_bytes,
                                                                    <<0>>,
                                                                    align_padding(
                                                                        110 + Name_size
                                                                    )]
                                                            ),
                                                            Body_with_padding = gleam_stdlib:bit_array_concat(
                                                                [Body,
                                                                    align_padding(
                                                                        Body_size
                                                                    )]
                                                            ),
                                                            {ok,
                                                                gleam_stdlib:bit_array_concat(
                                                                    [Header_with_name,
                                                                        Body_with_padding]
                                                                )}
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/packkit/cpio.gleam", 48).
?DOC(" Encode the logical archive to a newc byte stream.\n").
-spec encode(packkit@archive:archive()) -> {ok, bitstring()} |
    {error, packkit@error:archive_error()}.
encode(Archive_value) ->
    gleam@result:'try'(
        reject_comment(Archive_value),
        fun(_) -> _pipe = Archive_value,
            _pipe@1 = packkit@archive:entries(_pipe),
            _pipe@2 = gleam@list:try_map(_pipe@1, fun encode_entry/1),
            gleam@result:map(
                _pipe@2,
                fun(Blocks) ->
                    _pipe@3 = [gleam_stdlib:bit_array_concat(Blocks),
                        trailer_record()],
                    gleam_stdlib:bit_array_concat(_pipe@3)
                end
            ) end
    ).