change: rework to make more testable

laumann
Nov 27, 2023, 10:18 PM
SMB3M6ESOIR2LMFII2VFQJSPFIUYXHD7CXYARIGOKPB2QF2ORFLAC

Dependencies

  • [2] WH7UFRAZ change: close change files after load
  • [3] ZS3UJEZU change: support version = 4 (noenc) format
  • [4] 67HZZ5HS meson: shuffle lib and exe sources
  • [5] ZTDGWUGP add repository structure
  • [6] QSQNGA5K changestore: load changes on demand
  • [7] TGT4VSME change: decode FILE_ADD
  • [8] Q7TKZCJP Add initial support for reading the offsets from a (fixed) change
  • [9] VKLGQREY change: add base32 decode, initial deconstruction of hashed
  • [10] XV2V6J3L clean up Makefile
  • [11] WMFNGOYT change: reduce printed noise, rework some code
  • [12] NETL2N53 Makefile: add check target
  • [13] 3NA345CN Add zstd_seekable + many headers
  • [14] AEMTSEJX change: simplify readout of offsets
  • [15] N3PUHKQN change: fix scoping issue
  • [16] U3JWO63Y change: deduplicate some code repetition
  • [17] YG4DZB3A add representation of hash, decode dependencies
  • [18] BMTTQJX6 use meson builtin clang-format support
  • [19] VXQYIOBX change: avoid crash on different format versions
  • [20] L3HKOF4W wrap vendored zstd seekable in own file, #2
  • [21] WGGDK6VO change: use bincode decoder for decoding offsets
  • [22] 3FT3XTJM change: support -v/-h flags
  • [23] 7NQTS36D bincode: change signature of getstr to receive str destination
  • [24] JAGXXSR7 change: initial work on decoding hunks
  • [25] UVEPURUQ meson.build: build lib and link with main exe
  • [26] OBKF6SII change: decompress the hashed section too
  • [27] Y26WT3ZF change: decode message, description and timestamp
  • [28] RIWSVVAS change: decompress the 'contents' with zstd_seekable
  • [29] YDQLW2ZO change: rework printing of patches - print Edit and Newvertex types
  • [30] FMYCPGKD change: extract hash list decoding into reused function
  • [31] 4RYULBDD bincode: introduce a bincode_state struct
  • [32] LCEKN25G change: parse authors
  • [33] LVX6U4EK change: decode metadata bytes
  • [34] CJEOFJ27 change: minor output adjustment
  • [35] 55SITR55 change: decode replacements
  • [36] YM2LC6QP wrap vendored blake3 in own file, #2
  • [37] B3XLVPNC Add ani.c and initial Makefile
  • [38] KEC3WLFN change: remove debugging lines
  • [39] KDJUAAAL change: prefix function names with change_
  • [40] X36ICMJN Initial import for blake3
  • [41] XTKRT6OQ format the codebase
  • [42] QEFCNNVC change: display offsets for given change file
  • [43] 5D2IYPL7 change: introduce changestore, print deleted lines
  • [44] 3OHR6ZPH make: prettify output
  • [45] RRYWNHFE change: pass verbose to print_atom()
  • [46] 2U7P5SFQ Change struct names "struct foo -> typedef struct Foo"
  • [47] NZNIG2UL Fix lots of warnings, adjust build flags
  • [48] VXGUQZIV bincode: rework so functions advance pointer
  • [49] QYRJIOYP change: separate decoding and printing of hashed struct
  • [50] P5CSMRVS change: fix sequence-point warning
  • [51] IS5A7VT6 change: print hashes
  • [52] ZKAOPMCH change: Implement decoding of edits, atoms, positions, among others
  • [53] YFBKBUKB change: rename binstat -> bc
  • [54] XJ2PEH74 add meson.build
  • [55] WGYMYRCY Fix #3, settle on C11
  • [56] JVU3TTT5 all: switch away from typedefing anonymous structs
  • [57] WFA5BBRF Fix warnings
  • [*] PEUS54XQ

Change contents

  • file addition: test (d--r------)
    [59.1]
  • file addition: test_change.c (----------)
    [0.16]
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #undef NDEBUG
    #include <assert.h>
    #include "NETL2.h"
    #include "../common.h"
    #include "../zstdseek.h"
    #include "../types.h"
    #include "../scaffold.h"
    #include "../hash.h"
    #include "../vertex.h"
    #include "../atom.h"
    #include "../hunk.h"
    #include "../mbuf.h"
    #include "../change.h"
    static void
    test_changefileoffsets()
    {
    struct mbuf ch = {
    .len = NETL2LEN,
    .buf = NETL2,
    };
    struct offsets off = { 0 };
    int err;
    err = changefileoffsets(&ch, &off);
    assert(err == CHANGEFILE_OK);
    assert(off.version == VERSION);
    assert(off.hashed_len == 985);
    assert(off.unhashed_off = 803);
    assert(off.unhashed_len == 104);
    assert(off.contents_off == 945);
    assert(off.contents_len == 120);
    }
    static void
    test_changefileoffsetsbad()
    {
    struct mbuf ch = { .len = 55, .buf = NULL };
    int err;
    struct offsets off = { 0 };
    err = changefileoffsets(&ch, &off);
    assert(err == CHANGEFILE_TOOSHORT);
    }
    static void
    test_changefileoffsetsversion()
    {
    struct mbuf ch = {
    .len = NETL2LEN,
    .buf = NETL2,
    };
    struct offsets off = { 0 };
    int err;
    ch.buf[0] = 5;
    err = changefileoffsets(&ch, &off);
    assert(err == CHANGEFILE_UNSUPPORTEDVERSION);
    }
    static void
    test_decodehashed()
    {
    struct hashed hashed = { 0 };
    struct changeheader *header;
    struct author *author;
    usize datalen = 747;
    usize hashedlen = 985;
    u8 buf[hashedlen];
    enum error ret;
    usize err;
    u8 expectedhash[32] = { 0x69, 0x26, 0xbd, 0x37, 0xbb, 0x93, 0xa2, 0x5a,
    0xae, 0x27, 0x9e, 0x8c, 0xaf, 0x13, 0x08, 0x32,
    0xbd, 0xca, 0x78, 0x9c, 0x84, 0xc4, 0x49, 0x79,
    0xa6, 0x83, 0xc3, 0x8a, 0x3d, 0x0e, 0xa9, 0x10 };
    err = zstdseek_decompress(buf, hashedlen, NETL2 + 56, datalen);
    assert(err > 0);
    ret = change_decodehashed(buf, hashedlen, expectedhash, &hashed);
    assert(ret == CHANGEFILE_OK);
    assert(hashed.version == VERSION);
    header = &hashed.header;
    assert(strcmp(header->message, "Makefile: add check target") == 0);
    assert(header->description == NULL);
    assert(strcmp(header->timestamp, "2022-10-31T12:34:27.238139355Z") == 0
    );
    assert(header->authors.len == 1);
    author = &header->authors.map[0];
    assert(author->len == 1);
    assert(strcmp(author->entries[0].key, "key") == 0);
    assert(strcmp(author->entries[0].value,
    "AFgzZkD8ARgC21gkkCvxPV5HbL7YDVzgYEhbAxQG7UQY") == 0);
    assert(hashed.dependencies.len == 1);
    assert(hashed.extraknown.len == 4);
    /* assert hunks as expected */
    assert(hashed.hunks.len == 2);
    hashedfree(&hashed);
    }
    int
    main()
    {
    test_changefileoffsets();
    test_changefileoffsetsbad();
    test_changefileoffsetsversion();
    test_decodehashed();
    }
  • file addition: meson.build (----------)
    [0.16]
    cases = [
    'change',
    ]
    foreach testcase : cases
    srcs = files('test_@0@.c'.format(testcase))
    exe = executable('test_@0@'.format(testcase), srcs, link_with : lib)
    test(testcase, exe, suite : 'unit', timeout : 120)
    endforeach
  • file addition: NETL2.h (----------)
    [0.16]
    /**
    * A fairly simple change that has just two hunks: an edit and a replacement.
    */
    unsigned char NETL2[] = {
    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x03, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x4f, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xb5, 0x2f, 0xfd,
    0x00, 0x60, 0x95, 0x06, 0x00, 0x84, 0x0b, 0x06, 0x00, 0x1a, 0x4d, 0x61,
    0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x20, 0x61, 0x64, 0x64, 0x20,
    0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
    0x00, 0x1e, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x30, 0x2d, 0x33, 0x31,
    0x54, 0x31, 0x32, 0x3a, 0x33, 0x34, 0x3a, 0x32, 0x37, 0x2e, 0x32, 0x33,
    0x38, 0x31, 0x33, 0x39, 0x33, 0x35, 0x35, 0x5a, 0x01, 0x03, 0x6b, 0x65,
    0x79, 0x2c, 0x41, 0x46, 0x67, 0x7a, 0x5a, 0x6b, 0x44, 0x38, 0x41, 0x52,
    0x67, 0x43, 0x32, 0x31, 0x67, 0x6b, 0x6b, 0x43, 0x76, 0x78, 0x50, 0x56,
    0x35, 0x48, 0x62, 0x4c, 0x37, 0x59, 0x44, 0x56, 0x7a, 0x67, 0x59, 0x45,
    0x68, 0x62, 0x41, 0x78, 0x51, 0x47, 0x37, 0x55, 0x51, 0x59, 0xce, 0x1c,
    0x40, 0xeb, 0x89, 0x5a, 0xef, 0xf0, 0x24, 0xdc, 0x57, 0x1d, 0x3d, 0x8a,
    0x0a, 0xb3, 0x7c, 0x7b, 0x1c, 0x8d, 0x23, 0x74, 0xbe, 0xc1, 0x54, 0x69,
    0x68, 0x57, 0xf6, 0x52, 0xcb, 0x16, 0x04, 0x0e, 0xee, 0xba, 0xbd, 0xa2,
    0xe0, 0x9c, 0xb5, 0x8b, 0x65, 0xa1, 0x37, 0xcc, 0x7c, 0xe8, 0x54, 0xd8,
    0x5f, 0x09, 0x39, 0xa0, 0x25, 0x97, 0x53, 0x78, 0x66, 0xb0, 0x67, 0xe5,
    0x49, 0xcb, 0xff, 0x01, 0x00, 0x00, 0x00, 0xd0, 0xb4, 0x42, 0xe8, 0x09,
    0x00, 0x79, 0x6a, 0x3c, 0x4a, 0x81, 0x17, 0x97, 0x9c, 0x20, 0xf3, 0x0a,
    0xb1, 0x27, 0x95, 0x1d, 0x46, 0x65, 0x5f, 0xc9, 0x77, 0x00, 0x58, 0x28,
    0xb5, 0x2f, 0xfd, 0x00, 0x60, 0x85, 0x05, 0x00, 0x04, 0x0a, 0xca, 0x9b,
    0x81, 0x3f, 0xc1, 0x1d, 0xf2, 0x94, 0x32, 0x9a, 0x26, 0x91, 0x73, 0x11,
    0xbd, 0x54, 0x04, 0x9b, 0x02, 0x87, 0xd7, 0x80, 0xe2, 0xe0, 0x11, 0xef,
    0xcd, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xc3, 0x2d, 0x16, 0x4a, 0x1e, 0xad,
    0x06, 0x63, 0x03, 0xd2, 0xed, 0x42, 0x93, 0xeb, 0x6f, 0xcc, 0xb9, 0xc0,
    0xc8, 0xc5, 0x7b, 0xcf, 0xa0, 0xfa, 0x41, 0x82, 0x73, 0x12, 0xdc, 0x84,
    0x32, 0x86, 0x01, 0x00, 0x00, 0x00, 0x62, 0xfb, 0x76, 0x64, 0x94, 0xbb,
    0x24, 0x60, 0x76, 0xd2, 0xde, 0x5e, 0xd5, 0x3a, 0x34, 0xeb, 0x46, 0x0a,
    0x6a, 0xf8, 0x57, 0xbf, 0xe1, 0xdb, 0xd0, 0x35, 0xcf, 0x00, 0x39, 0x62,
    0x77, 0xc8, 0x00, 0x02, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0xee,
    0xba, 0xbd, 0xa2, 0xe0, 0x9c, 0xb5, 0x8b, 0x65, 0xa1, 0x37, 0xcc, 0x7c,
    0xe8, 0x54, 0xd8, 0x5f, 0x09, 0x39, 0xa0, 0x25, 0x97, 0x53, 0x78, 0x66,
    0xb0, 0x67, 0xe5, 0x49, 0xcb, 0xff, 0xa5, 0x02, 0x00, 0x52, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0xee,
    0xba, 0xbd, 0x05, 0x00, 0x06, 0xac, 0xd0, 0x83, 0x77, 0xc0, 0xb1, 0x15,
    0x27, 0xa5, 0x0b, 0xcc, 0x28, 0xb5, 0x2f, 0xfd, 0x00, 0x60, 0x35, 0x04,
    0x00, 0x64, 0x06, 0xa2, 0xe0, 0x9c, 0xb5, 0x8b, 0x65, 0xa1, 0x37, 0xcc,
    0x7c, 0xe8, 0x54, 0xd8, 0x5f, 0x09, 0x39, 0xa0, 0x25, 0x97, 0x53, 0x78,
    0x66, 0xb0, 0x67, 0xe5, 0x49, 0xcb, 0xff, 0xca, 0x01, 0x00, 0x08, 0x00,
    0x4d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x2f, 0x01, 0x05, 0x55,
    0x54, 0x46, 0x2d, 0x38, 0x07, 0x00, 0x00, 0x00, 0x01, 0x81, 0x01, 0x01,
    0x00, 0x00, 0x00, 0x0e, 0xee, 0xba, 0xbd, 0xfe, 0x02, 0xce, 0x1c, 0x40,
    0xeb, 0x89, 0x5a, 0xef, 0xf0, 0x24, 0xdc, 0x57, 0x1d, 0x3d, 0x8a, 0x0a,
    0xb3, 0x7c, 0x7b, 0x1c, 0x8d, 0x23, 0x74, 0xbe, 0xc1, 0x54, 0x69, 0x68,
    0x57, 0xf6, 0x52, 0xcb, 0x16, 0x15, 0x06, 0x33, 0x06, 0x0c, 0x00, 0x0a,
    0x73, 0x03, 0xb0, 0x32, 0x58, 0x00, 0x1f, 0xaa, 0x06, 0x00, 0xc3, 0x68,
    0x60, 0x0c, 0xea, 0x82, 0x5d, 0x46, 0x2c, 0x19, 0xcf, 0xcc, 0x07, 0x0c,
    0xfe, 0x02, 0x4e, 0x28, 0xb5, 0x2f, 0xfd, 0x00, 0x60, 0xf5, 0x03, 0x00,
    0x24, 0x06, 0x78, 0x66, 0xb0, 0x67, 0xe5, 0x49, 0xcb, 0xff, 0xca, 0x01,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0xee, 0xba, 0xbd, 0xa2, 0xe0,
    0x9c, 0xb5, 0x8b, 0x65, 0xa1, 0x37, 0xcc, 0x7c, 0xe8, 0x54, 0xd8, 0x5f,
    0x09, 0x39, 0xa0, 0x25, 0x97, 0x53, 0xfe, 0x02, 0x00, 0x01, 0x53, 0x77,
    0x08, 0x4d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x37, 0x05, 0x55,
    0x54, 0x46, 0x2d, 0x38, 0x01, 0x00, 0x00, 0x00, 0x2b, 0xec, 0x22, 0x87,
    0xe4, 0xa3, 0x3f, 0x21, 0x88, 0x9a, 0x3e, 0x30, 0x84, 0xe3, 0xf1, 0xcb,
    0x56, 0xc1, 0x0f, 0x17, 0xf3, 0x09, 0x01, 0x7d, 0x56, 0x5d, 0xba, 0x1a,
    0xf8, 0x91, 0x99, 0xc3, 0x0a, 0x00, 0xac, 0x2c, 0x90, 0x40, 0x0e, 0x6b,
    0x3e, 0x81, 0x11, 0x51, 0x12, 0xcc, 0x65, 0x71, 0x31, 0xee, 0x8c, 0xb8,
    0x22, 0xee, 0x42, 0x40, 0x01, 0xbc, 0x5e, 0x2a, 0x4d, 0x18, 0x39, 0x00,
    0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0xe1,
    0xe4, 0xb8, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x86, 0xdf,
    0x60, 0x45, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x88, 0x6d,
    0x55, 0x04, 0x87, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x42, 0x33,
    0x02, 0x89, 0x04, 0x00, 0x00, 0x00, 0x80, 0xb1, 0xea, 0x92, 0x8f, 0x28,
    0xb5, 0x2f, 0xfd, 0x00, 0x60, 0x41, 0x03, 0x00, 0x7b, 0x22, 0x73, 0x69,
    0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22, 0x35, 0x46,
    0x57, 0x4d, 0x47, 0x79, 0x53, 0x46, 0x33, 0x32, 0x6f, 0x58, 0x6d, 0x73,
    0x6a, 0x48, 0x64, 0x61, 0x67, 0x5a, 0x65, 0x6e, 0x4b, 0x57, 0x45, 0x35,
    0x67, 0x79, 0x78, 0x50, 0x51, 0x65, 0x52, 0x4d, 0x43, 0x48, 0x41, 0x50,
    0x51, 0x41, 0x59, 0x6d, 0x65, 0x46, 0x59, 0x7a, 0x63, 0x64, 0x6b, 0x5a,
    0x73, 0x42, 0x6e, 0x31, 0x43, 0x43, 0x4d, 0x52, 0x67, 0x66, 0x72, 0x53,
    0x42, 0x51, 0x36, 0x77, 0x61, 0x63, 0x50, 0x51, 0x79, 0x79, 0x67, 0x62,
    0x4e, 0x50, 0x31, 0x67, 0x78, 0x7a, 0x4d, 0x52, 0x61, 0x6b, 0x34, 0x45,
    0x32, 0x73, 0x22, 0x7d, 0x5e, 0x2a, 0x4d, 0x18, 0x15, 0x00, 0x00, 0x00,
    0x71, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6a, 0xa6, 0x03, 0x07,
    0x01, 0x00, 0x00, 0x00, 0x80, 0xb1, 0xea, 0x92, 0x8f, 0x28, 0xb5, 0x2f,
    0xfd, 0x00, 0x60, 0xc1, 0x03, 0x00, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x3a,
    0x20, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x0a, 0x09, 0x2e, 0x2f, 0x61, 0x6e,
    0x69, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x41, 0x47, 0x42,
    0x4c, 0x51, 0x4f, 0x51, 0x49, 0x42, 0x36, 0x44, 0x53, 0x44, 0x32, 0x41,
    0x50, 0x4f, 0x36, 0x4c, 0x32, 0x50, 0x4c, 0x46, 0x58, 0x46, 0x37, 0x43,
    0x52, 0x57, 0x4b, 0x41, 0x44, 0x36, 0x56, 0x41, 0x57, 0x49, 0x41, 0x44,
    0x36, 0x46, 0x32, 0x44, 0x54, 0x48, 0x34, 0x45, 0x49, 0x52, 0x59, 0x52,
    0x51, 0x43, 0x0a, 0x0a, 0x00, 0x2e, 0x50, 0x48, 0x4f, 0x4e, 0x59, 0x3a,
    0x20, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x20, 0x66, 0x6d, 0x74, 0x20, 0x62,
    0x75, 0x69, 0x6c, 0x64, 0x20, 0x67, 0x72, 0x61, 0x70, 0x68, 0x20, 0x63,
    0x68, 0x65, 0x63, 0x6b, 0x0a, 0x00, 0x5e, 0x2a, 0x4d, 0x18, 0x15, 0x00,
    0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x41, 0x5a,
    0x84, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x80, 0xb1, 0xea, 0x92, 0x8f
    };
    unsigned int NETL2LEN = 1103;
  • replacement in meson.build at line 6
    [6.80][6.80:375]()
    '-g3',
    '-D_POSIX_C_SOURCE=200809L',
    # Extra flags from https://nullprogram.com/blog/2023/04/29/
    '-Wdouble-promotion',
    '-Wconversion',
    #'-fsanitize-undefined-trap-on-error',
    #'-fsanitize=address', # can't have this one because of the assembly :-(
    '-fno-diagnostics-color',
    language: 'c'
    [6.80]
    [6.375]
    '-g3',
    '-D_POSIX_C_SOURCE=200809L',
    # Extra flags from https://nullprogram.com/blog/2023/04/29/
    '-Wdouble-promotion',
    '-Wconversion',
    #'-fsanitize-undefined-trap-on-error',
    #'-fsanitize=address', # can't have this one because of the assembly :-(
    '-fno-diagnostics-color',
    language: 'c'
  • edit in meson.build at line 30
    [6.1411]
    [6.1411]
    'mbuf.c',
  • edit in meson.build at line 33
    [6.14]
    [6.357]
    'change.c'
  • edit in meson.build at line 46
    [4.124][4.124:137]()
    'change.c'
  • replacement in meson.build at line 48
    [4.193][6.117:118](),[6.117][6.117:118]()
    [4.193]
    subdir('test')
  • file addition: mbuf.h (----------)
    [59.1]
    #ifndef ANI_CHANGEFILE_H
    #define ANI_CHANGEFILE_H
    struct mbuf {
    size len;
    u8 *buf;
    };
    /**
    * Populate a changefile from a file descriptor - returns a negative
    * number to indicate some kind of failure.
    */
    int mkmbuf(int fd, struct mbuf *);
    /**
    * Free an mbuf
    */
    void freembuf(struct mbuf *b);
    #endif
  • file addition: mbuf.c (----------)
    [59.1]
    #include <stdint.h>
    #include <stddef.h>
    #include <sys/stat.h>
    #include <sys/mman.h>
    #include "common.h"
    #include "scaffold.h"
    #include "types.h"
    #include "mbuf.h"
    // https://nullprogram.com/blog/2023/09/27/
    // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1428r0.pdf
    // mmap()
    int
    mkmbuf(int fd, struct mbuf *ch)
    {
    struct stat sb = { 0 };
    u8 *addr;
    if (fstat(fd, &sb) == -1)
    return -1;
    addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (addr == MAP_FAILED)
    return -1;
    ch->buf = addr;
    ch->len = sb.st_size;
    return 0;
    }
    void
    freembuf(struct mbuf *b)
    {
    /* FIXME check return code of munmap() */
    munmap(b->buf, (usize)b->len);
    }
  • edit in change.h at line 26
    [6.638][6.638:692]()
    /* sizeof(struct offsets) */
    #define OFFSETS_SIZE 56
  • replacement in change.h at line 27
    [6.696][6.696:766]()
    * The possible errors that can arise when working with change files.
    [6.696]
    [6.766]
    * Errors that can arise when working with change files
  • replacement in change.h at line 29
    [6.770][6.770:806]()
    enum change_err {
    VERMISMATCH = -1
    [6.770]
    [6.806]
    enum error {
    /* all good */
    CHANGEFILE_OK,
    /* .change file is too short */
    CHANGEFILE_TOOSHORT,
    /* .change file length mismatch */
    CHANGEFILE_LENGTHMISMATCH,
    /* version specified in file is not supported */
    CHANGEFILE_UNSUPPORTEDVERSION,
    /* hash mismatch */
    CHANGEFILE_HASHMISMATCH,
  • edit in change.h at line 46
    [6.810]
    [6.1740]
    enum error changefileoffsets(struct mbuf *, struct offsets *);
    /* sizeof(struct offsets) */
    #define OFFSETS_SIZE 56
  • edit in change.h at line 104
    [6.2396]
    [6.1114]
    /**
    * Decompress and decode the hashed parts of a .change file. The
    * struct hashed pointer argument is populated with the result.
    *
    */
    enum error change_decodehashed(u8 *, usize, u8 *, struct hashed *);
  • edit in change.c at line 11
    [6.2445]
    [6.574]
    #include "types.h"
  • edit in change.c at line 20
    [6.962]
    [6.1192]
    #include "mbuf.h"
  • replacement in change.c at line 25
    [6.1][6.963:975](),[6.975][6.6:59](),[6.6][6.6:59]()
    static void
    dump_buf(const char *name, uint8_t *buf, size_t len)
    [6.1]
    [6.59]
    enum error
    changefileoffsets(struct mbuf *ch, struct offsets *off)
  • edit in change.c at line 28
    [6.61][6.378:389](),[6.69][6.1488:1489](),[6.389][6.1488:1489](),[6.1488][6.1488:1489](),[6.1489][6.70:130](),[6.130][6.712:747](),[6.747][6.167:194](),[6.167][6.167:194](),[6.194][6.748:774](),[6.774][6.222:238](),[6.222][6.222:238](),[6.238][6.0:3](),[6.241][6.1489:1493](),[6.1489][6.1489:1493](),[6.1493][6.2397:2448](),[6.51][6.1537:1539](),[6.2448][6.1537:1539](),[6.2490][6.1537:1539](),[6.1537][6.1537:1539](),[6.1547][6.1547:1587]()
    size_t i;
    if (len == 0) {
    printf("%s = []\n", name);
    return;
    }
    printf("%s = [%u", name, buf[0]);
    for (i = 1; i < len; i++)
    printf(", %u", buf[i]);
    printf("]\n");
    }
    int
    change_decode_offsets(int fd, struct offsets *off)
    {
    ssize_t r;
    uint8_t buf[OFFSETS_SIZE];
  • replacement in change.c at line 30
    [6.1604][6.1604:1848]()
    if ((r = read(fd, buf, OFFSETS_SIZE)) < OFFSETS_SIZE) {
    int err;
    if (r >= 0) {
    printf("error: not enough was read: %ld\n", r);
    err = -2;
    } else {
    printf("error: not enough was read: %ld\n", r);
    err = -1;
    }
    return err;
    }
    [6.1604]
    [6.32]
    if (ch->len < OFFSETS_SIZE)
    return CHANGEFILE_TOOSHORT;
  • replacement in change.c at line 33
    [6.33][6.21:36]()
    bc.buf = buf;
    [6.33]
    [6.36]
    bc.buf = ch->buf;
  • replacement in change.c at line 44
    [6.2184][6.2184:2195]()
    return 0;
    [6.2184]
    [6.2195]
    if (off->total != (u64)ch->len)
    return CHANGEFILE_LENGTHMISMATCH;
    switch (off->version) {
    case VERSION:
    case VERSION_NOENC:
    return CHANGEFILE_OK;
    default:
    return CHANGEFILE_UNSUPPORTEDVERSION;
    }
  • replacement in change.c at line 56
    [6.2198][6.0:4](),[6.4][6.242:417](),[6.417][6.608:612](),[6.608][6.608:612](),[6.612][6.418:435](),[6.435][6.729:802]()
    /**
    * Read in an expected amount of bytes (or die failing), and decompress with
    * zstd-seekable. Return a malloc()'ed byte buffer that the caller is in charge
    * of free()'ing.
    */
    static uint8_t *
    decompress_segment(int fd, size_t compressed_len, uint64_t expected_len)
    [6.2198]
    [6.665]
    static char *
    change_strerror(enum error err)
  • replacement in change.c at line 59
    [6.813][6.813:850](),[6.878][6.878:904](),[6.924][6.924:940](),[6.940][6.940:941](),[6.585][6.585:640](),[6.640][6.1129:1198](),[6.1129][6.1129:1198]()
    uint8_t *compressed;
    uint8_t *buf;
    ssize_t compressed_read;
    size_t result;
    compressed = calloc(sizeof(uint8_t), compressed_len);
    if (compressed == NULL) {
    perror("malloc compressed");
    exit(1);
    [6.667]
    [6.1198]
    switch (err) {
    case CHANGEFILE_OK:
    return "ok";
    case CHANGEFILE_TOOSHORT:
    return ".change file is too short";
    case CHANGEFILE_LENGTHMISMATCH:
    return "length in .change file mismatch with actual length";
    case CHANGEFILE_UNSUPPORTEDVERSION:
    return ".change file version not supported";
    case CHANGEFILE_HASHMISMATCH:
    return "hash mismatch";
  • replacement in change.c at line 71
    [6.1201][6.641:687](),[6.687][6.1252:1307](),[6.1252][6.1252:1307](),[6.1307][6.1307:1310](),[6.1310][6.1310:1311](),[6.1311][6.1311:1344](),[6.1344][6.688:745](),[6.745][6.390:441](),[6.441][6.1451:1517](),[6.787][6.1451:1517](),[6.1451][6.1451:1517](),[6.1517][6.803:840](),[6.826][6.1559:1574](),[6.840][6.1559:1574](),[6.1559][6.1559:1574](),[6.1574][6.1574:1577](),[6.207][6.1631:1632](),[6.1631][6.1631:1632](),[6.1632][6.1451:1559](),[6.1559][6.1751:1752](),[6.1751][6.1751:1752](),[6.2521][6.2521:2591]()
    buf = calloc(sizeof(uint8_t), expected_len);
    if (buf == NULL) {
    perror("malloc buf");
    exit(1);
    }
    /* Read data into compressed */
    compressed_read = read(fd, compressed, compressed_len);
    if (compressed_read != (ssize_t)compressed_len) {
    fprintf(stderr, "error: Expected to read %lu bytes, got %lu\n",
    compressed_len, compressed_read);
    goto errout;
    }
    result = zstdseek_decompress(
    buf, expected_len, compressed, compressed_len
    );
    if (result)
    goto out;
    errout:
    free(buf);
    buf = NULL;
    out:
    free(compressed);
    return buf;
    [6.1201]
    [6.0]
    die("unhandled error variant: %d\n", err);
  • edit in change.c at line 222
    [6.4355]
    [6.4355]
    }
    static u64
    change_readstr(char **dest, struct bincode *bc)
    {
    u64 len;
    len = bincode_getu64(bc);
    *dest = xmalloc(len + 1);
    bincode_getstr(bc, *dest, len);
    return len;
  • replacement in change.c at line 237
    [6.4424][6.4424:4440](),[6.4440][6.2704:2731](),[6.2731][6.0:72]()
    uint64_t len;
    len = bincode_getu64(bc);
    local->path = xmalloc(len + 1);
    bincode_getstr(bc, local->path, len);
    [6.4424]
    [6.2771]
    change_readstr(&local->path, bc);
  • replacement in change.c at line 246
    [6.2894][6.2894:2931](),[6.2931][6.73:143]()
    uint64_t len = bincode_getu64(bc);
    *encoding = xmalloc(len + 1);
    bincode_getstr(bc, *encoding, len);
    [6.2894]
    [6.3751]
    change_readstr(encoding, bc);
  • replacement in change.c at line 300
    [6.3653][6.3653:3683](),[6.3683][6.144:238]()
    slen = bincode_getu64(bc);
    bhunk->fileadd.path = xmalloc(slen + 1);
    bincode_getstr(bc, bhunk->fileadd.path, slen);
    [6.3653]
    [3.476]
    change_readstr(&bhunk->fileadd.path, bc);
  • edit in change.c at line 394
    [3.905][3.905:1067]()
    for (i = 0; i < author->len; i++) {
    len = bincode_getu64(bc);
    author->entries[i].key = xmalloc(len + 1);
    bincode_getstr(bc, author->entries[i].key, len);
  • replacement in change.c at line 395
    [3.1068][3.1068:1196]()
    len = bincode_getu64(bc);
    author->entries[i].value = xmalloc(len + 1);
    bincode_getstr(bc, author->entries[i].value, len);
    [3.1068]
    [3.1196]
    for (i = 0; i < len; i++) {
    change_readstr(&author->entries[i].key, bc);
    change_readstr(&author->entries[i].value, bc);
  • replacement in change.c at line 404
    [3.1279][3.1279:1295]()
    size_t len, i;
    [3.1279]
    [3.1295]
    usize i;
  • replacement in change.c at line 410
    [3.1365][3.1365:1450]()
    len = bincode_getu64(bc);
    name = xmalloc(len + 1);
    bincode_getstr(bc, name, len);
    [3.1365]
    [3.1450]
    change_readstr(&name, bc);
  • replacement in change.c at line 414
    [3.1484][3.1484:1582]()
    len = bincode_getu64(bc);
    full_name = xmalloc(len + 1);
    bincode_getstr(bc, full_name, len);
    [3.1484]
    [3.1582]
    change_readstr(&full_name, bc);
  • replacement in change.c at line 419
    [3.1619][3.1619:1709]()
    len = bincode_getu64(bc);
    email = xmalloc(len + 1);
    bincode_getstr(bc, email, len);
    [3.1619]
    [3.1709]
    change_readstr(&email, bc);
  • replacement in change.c at line 441
    [6.626][6.1068:1079](),[6.1068][6.1068:1079](),[6.1079][6.5533:5544](),[6.5544][6.985:1059](),[6.1083][6.985:1059](),[6.1059][6.3754:3801]()
    /**
    *
    */
    static int
    change_decode_hashed(
    int fd, size_t comp_hashed_len, size_t hashed_len,
    uint8_t *expected_hash, struct hashed *hashed
    [6.626]
    [6.1083]
    enum error
    change_decodehashed(
    u8 *data, usize datalen, u8 *expectedhash, struct hashed *hashed
  • replacement in change.c at line 446
    [6.1157][6.1157:1172](),[6.1172][6.36:72](),[6.72][6.950:961](),[6.347][6.950:961](),[6.950][6.950:961](),[6.961][6.348:362](),[6.362][6.633:648]()
    uint8_t *buf;
    uint8_t computed_hash[BLAKE3_LEN];
    size_t i;
    int err = 0;
    uint64_t len;
    [6.1157]
    [6.5284]
    u8 computedhash[BLAKE3_LEN];
  • edit in change.c at line 448
    [6.5304]
    [3.2099]
    u64 len;
    usize i;
  • replacement in change.c at line 452
    [6.2592][6.1173:1332]()
    buf = decompress_segment(fd, comp_hashed_len, hashed_len);
    if (buf == NULL) {
    fprintf(stderr, "error: failed to decompress hashed segment\n");
    return 1;
    [6.2592]
    [6.1332]
    /*Step 1. Compute the hash */
    if (expectedhash != NULL) {
    blake3_hash(computedhash, data, datalen);
    if (blake3_cmp(computedhash, expectedhash))
    return CHANGEFILE_HASHMISMATCH;
  • replacement in change.c at line 459
    [6.1004][6.1004:1055](),[6.1055][6.73:119](),[6.119][6.1055:1056](),[6.1055][6.1055:1056](),[6.1274][6.1274:1304](),[6.1304][6.120:170](),[6.170][6.476:489](),[6.476][6.476:489](),[6.489][6.1086:1153](),[6.1153][6.171:207](),[6.207][6.592:674](),[6.592][6.592:674](),[6.674][6.208:244](),[6.244][6.714:791](),[6.714][6.714:791](),[6.791][6.1396:1399](),[6.1396][6.1396:1399]()
    /* Step 1. Compute the hash of the result buf! */
    blake3_hash(computed_hash, buf, hashed_len);
    if (expected_hash != NULL) {
    err = blake3_cmp(computed_hash, expected_hash);
    if (err) {
    fprintf(stderr,
    "error: change hash mismatch, claimed \n");
    for (i = 0; i < BLAKE3_LEN; i++)
    fprintf(stderr, "%02x", expected_hash[i]);
    fprintf(stderr, ", computed ");
    for (i = 0; i < BLAKE3_LEN; i++)
    fprintf(stderr, "%02x", expected_hash[i]);
    fprintf(stderr, "\n");
    }
    }
    [6.963]
    [6.649]
    bc.avail = datalen;
    bc.buf = data;
  • edit in change.c at line 462
    [6.650][6.5305:5344](),[6.92][6.696:697](),[6.119][6.696:697](),[6.5344][6.696:697](),[6.696][6.696:697]()
    bc.avail = hashed_len;
    bc.buf = buf;
  • replacement in change.c at line 463
    [6.138][6.802:803](),[6.5385][6.802:803](),[6.802][6.802:803](),[6.803][6.5386:5414](),[6.5414][6.773:868]()
    len = bincode_getu64(&bc);
    hashed->header.message = xmalloc(len + 1);
    bincode_getstr(&bc, hashed->header.message, len);
    [6.5385]
    [6.853]
    change_readstr(&hashed->header.message, &bc);
  • edit in change.c at line 465
    [6.967][6.967:1130]()
    /**
    * Description! This is like the commit "body", and is optional, so we
    * have a byte indicating its presence, '0' = None, '1' =
    * Some(description)
    */
  • replacement in change.c at line 467
    [6.5494][6.5494:5523](),[6.5523][6.869:974]()
    len = bincode_getu64(&bc);
    hashed->header.description = xmalloc(len + 1);
    bincode_getstr(&bc, hashed->header.description, len);
    [6.5494]
    [6.259]
    change_readstr(&hashed->header.description, &bc);
  • replacement in change.c at line 470
    [6.1368][6.5581:5609](),[6.251][6.1399:1400](),[6.417][6.1399:1400](),[6.832][6.1399:1400](),[6.1418][6.1399:1400](),[6.5609][6.1399:1400](),[6.1399][6.1399:1400]()
    len = bincode_getu64(&bc);
    [6.1368]
    [6.1419]
    len = change_readstr(&hashed->header.timestamp, &bc);
  • replacement in change.c at line 472
    [6.1435][6.1154:1248](),[6.1248][6.975:1074]()
    printf("warning: timestamp field has unexpected length %lu (expected 30)\n",
    len);
    hashed->header.timestamp = xmalloc(len + 1);
    bincode_getstr(&bc, hashed->header.timestamp, len);
    [6.1435]
    [6.354]
    fprintf(stderr,
    "warning: timestamp field has unexpected length %lu\n",
    len);
  • replacement in change.c at line 476
    [6.355][6.5665:5717]()
    len = bincode_getu64(&bc); /* arrays of authors */
    [6.355]
    [6.323]
    len = bincode_getu64(&bc);
  • edit in change.c at line 504
    [6.4708][6.278:279](),[6.5674][6.278:279](),[6.6090][6.278:279](),[6.278][6.278:279](),[6.279][6.279:303](),[6.303][6.1373:1385](),[6.1400][6.1373:1385](),[6.1641][6.1373:1385](),[6.2220][6.1373:1385](),[6.1373][6.1373:1385]()
    /* Hash of contents */
    free(buf);
  • replacement in change.c at line 505
    [6.1386][6.833:846]()
    return err;
    [6.1386]
    [6.1397]
    return CHANGEFILE_OK;
  • edit in change.c at line 509
    [6.1404][6.1404:1722](),[6.1722][6.3939:3989](),[6.3270][6.1772:1774](),[6.3989][6.1772:1774](),[6.1772][6.1772:1774](),[6.1774][6.1936:2024](),[6.2024][6.1691:1698]()
    * Read the contents section of the open change file, decompress it and return
    * the raw bytes.
    *
    * Returns a malloc()'ed byte buffer that the caller is responsible for
    * deallocating. Returns NULL if the full contents could not be read, or the
    * decompression failed, or some other error occurred.
    */
    uint8_t *
    change_read_contents(int fd, struct offsets *off)
    {
    return decompress_segment(
    fd, off->total - off->contents_off, off->contents_len
    );
    }
    /**
  • replacement in change.c at line 937
    [6.6729][6.6729:6763]()
    const char *hashstr, int verbose
    [6.6729]
    [6.6763]
    const char *hashstr
  • edit in change.c at line 941
    [6.6781]
    [6.6781]
    enum error cherr;
  • edit in change.c at line 943
    [6.6813]
    [6.6813]
    struct mbuf buf = { 0 };
  • replacement in change.c at line 946
    [6.6859][6.6859:6887]()
    uint8_t contents_hash[32];
    [6.6859]
    [6.6887]
    u8 contents_hash[32];
    u8 *scratch;
    usize r;
  • edit in change.c at line 960
    [6.2471]
    [6.2471]
    }
    err = mkmbuf(fd, &buf);
    if (err) {
    printf("error: %s\n", strerror(errno));
    goto out2;
  • replacement in change.c at line 973
    [6.2475][6.7237:7276](),[6.143][6.2508:2572](),[6.7276][6.2508:2572](),[6.2508][6.2508:2572]()
    err = change_decode_offsets(fd, off);
    if (err != 0) {
    printf("error: failed to decode offsets\n");
    [6.2475]
    [6.1858]
    cherr = changefileoffsets(&buf, off);
    if (cherr != CHANGEFILE_OK) {
    printf("error: %s\n", change_strerror(cherr));
    err = (int)cherr;
  • replacement in change.c at line 980
    [6.1874][3.3378:3544]()
    if (off->version != VERSION && off->version != VERSION_NOENC) {
    printf("Version %lu is not yet supported, sorry.\n",
    off->version);
    err = off->version;
    [6.1874]
    [6.540]
    scratch = xmalloc(sizeof(u8) * off->hashed_len);
    r = zstdseek_decompress(
    scratch, off->hashed_len, buf.buf + OFFSETS_SIZE,
    off->unhashed_off - OFFSETS_SIZE
    );
    if (!r) {
    err = 1;
    free(scratch);
  • replacement in change.c at line 990
    [6.555][6.555:556](),[6.556][6.2127:2156](),[6.1874][6.2127:2156](),[6.2156][6.7401:7482]()
    err = change_decode_hashed(
    fd, off->unhashed_off - OFFSETS_SIZE, off->hashed_len,
    contents_hash, hashed
    [6.555]
    [6.2227]
    err = change_decodehashed(
    scratch, off->hashed_len, contents_hash, hashed
  • edit in change.c at line 993
    [6.2231]
    [6.1956]
    free(scratch);
  • replacement in change.c at line 1000
    [6.949][6.1003:1116](),[6.1116][6.7483:7543](),[6.322][6.1168:1199](),[6.7543][6.1168:1199](),[6.1168][6.1168:1199]()
    /**
    * Seek to the point in the file where contents begin. Keep in mind,
    * we've already read 56 bytes.
    */
    if (lseek(fd, (off_t)off->contents_off, SEEK_SET) == -1) {
    perror("lseek");
    goto out;
    [6.949]
    [6.1199]
    c->contents = xmalloc(sizeof(u8) * off->contents_len);
    r = zstdseek_decompress(
    c->contents, off->contents_len, buf.buf + off->contents_off,
    off->total - off->contents_off
    );
    if (!r) {
    err = 1;
    free(c->contents);
  • replacement in change.c at line 1009
    [6.1202][6.7544:7590]()
    c->contents = change_read_contents(fd, off);
    [6.1202]
    [6.7647]
    err = 0;
  • edit in change.c at line 1011
    [6.7652]
    [2.0]
    freembuf(&buf);
    out2:
  • replacement in change.c at line 1022
    [6.7779][6.7779:7867]()
    struct change *c, struct hash *h, const char *repodir,
    struct hash *hash, int verbose
    [6.7779]
    [6.7867]
    struct change *c, struct hash *h, const char *repodir, struct hash *hash
  • replacement in change.c at line 1030
    [6.7995][6.7995:8048]()
    return loadchange(c, h, repodir, hashstr, verbose);
    [6.7995]
    [6.430]
    return loadchange(c, h, repodir, hashstr);
  • replacement in change.c at line 1068
    [6.1194][6.1194:1263]()
    err = loadchangeh(&ch->change, &ch->hash, store->repodir, hash, 0);
    [6.1194]
    [6.1263]
    err = loadchangeh(&ch->change, &ch->hash, store->repodir, hash);
  • replacement in change.c at line 1149
    [6.8361][5.561:631]()
    err = loadchange(&ch->change, &ch->hash, repo->path, hash, verbose);
    [6.8361]
    [6.8428]
    err = loadchange(&ch->change, &ch->hash, repo->path, hash);
  • replacement in change.c at line 1151
    [6.8438][6.8438:8452]()
    return err;
    [6.8438]
    [6.0]
    goto changeout;
  • replacement in Makefile at line 25
    [6.677][6.0:13](),[6.13][6.139:211]()
    check: build
    build/ani change NETL2N53SORFVLRHT2GK6EYIGK64U6E4QTCES6NGQPBYUPIOVEIAC
    [6.677]
    [6.81]
    check:
    @$(MESON) test -C build