Coverage Report

Created: 2024-09-08 06:23

/src/git/chunk-format.c
Line
Count
Source (jump to first uncovered line)
1
#define USE_THE_REPOSITORY_VARIABLE
2
3
#include "git-compat-util.h"
4
#include "chunk-format.h"
5
#include "csum-file.h"
6
#include "gettext.h"
7
#include "hash.h"
8
#include "trace2.h"
9
10
/*
11
 * When writing a chunk-based file format, collect the chunks in
12
 * an array of chunk_info structs. The size stores the _expected_
13
 * amount of data that will be written by write_fn.
14
 */
15
struct chunk_info {
16
  uint32_t id;
17
  uint64_t size;
18
  chunk_write_fn write_fn;
19
20
  const void *start;
21
};
22
23
struct chunkfile {
24
  struct hashfile *f;
25
26
  struct chunk_info *chunks;
27
  size_t chunks_nr;
28
  size_t chunks_alloc;
29
};
30
31
struct chunkfile *init_chunkfile(struct hashfile *f)
32
0
{
33
0
  struct chunkfile *cf = xcalloc(1, sizeof(*cf));
34
0
  cf->f = f;
35
0
  return cf;
36
0
}
37
38
void free_chunkfile(struct chunkfile *cf)
39
0
{
40
0
  if (!cf)
41
0
    return;
42
0
  free(cf->chunks);
43
0
  free(cf);
44
0
}
45
46
int get_num_chunks(struct chunkfile *cf)
47
0
{
48
0
  return cf->chunks_nr;
49
0
}
50
51
void add_chunk(struct chunkfile *cf,
52
         uint32_t id,
53
         size_t size,
54
         chunk_write_fn fn)
55
0
{
56
0
  ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
57
58
0
  cf->chunks[cf->chunks_nr].id = id;
59
0
  cf->chunks[cf->chunks_nr].write_fn = fn;
60
0
  cf->chunks[cf->chunks_nr].size = size;
61
0
  cf->chunks_nr++;
62
0
}
63
64
int write_chunkfile(struct chunkfile *cf, void *data)
65
0
{
66
0
  int i, result = 0;
67
0
  uint64_t cur_offset = hashfile_total(cf->f);
68
69
0
  trace2_region_enter("chunkfile", "write", the_repository);
70
71
  /* Add the table of contents to the current offset */
72
0
  cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
73
74
0
  for (i = 0; i < cf->chunks_nr; i++) {
75
0
    hashwrite_be32(cf->f, cf->chunks[i].id);
76
0
    hashwrite_be64(cf->f, cur_offset);
77
78
0
    cur_offset += cf->chunks[i].size;
79
0
  }
80
81
  /* Trailing entry marks the end of the chunks */
82
0
  hashwrite_be32(cf->f, 0);
83
0
  hashwrite_be64(cf->f, cur_offset);
84
85
0
  for (i = 0; i < cf->chunks_nr; i++) {
86
0
    off_t start_offset = hashfile_total(cf->f);
87
0
    result = cf->chunks[i].write_fn(cf->f, data);
88
89
0
    if (result)
90
0
      goto cleanup;
91
92
0
    if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
93
0
      BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
94
0
          cf->chunks[i].size, cf->chunks[i].id,
95
0
          hashfile_total(cf->f) - start_offset);
96
0
  }
97
98
0
cleanup:
99
0
  trace2_region_leave("chunkfile", "write", the_repository);
100
0
  return result;
101
0
}
102
103
int read_table_of_contents(struct chunkfile *cf,
104
         const unsigned char *mfile,
105
         size_t mfile_size,
106
         uint64_t toc_offset,
107
         int toc_length,
108
         unsigned expected_alignment)
109
0
{
110
0
  int i;
111
0
  uint32_t chunk_id;
112
0
  const unsigned char *table_of_contents = mfile + toc_offset;
113
114
0
  ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
115
116
0
  while (toc_length--) {
117
0
    uint64_t chunk_offset, next_chunk_offset;
118
119
0
    chunk_id = get_be32(table_of_contents);
120
0
    chunk_offset = get_be64(table_of_contents + 4);
121
122
0
    if (!chunk_id) {
123
0
      error(_("terminating chunk id appears earlier than expected"));
124
0
      return 1;
125
0
    }
126
0
    if (chunk_offset % expected_alignment != 0) {
127
0
      error(_("chunk id %"PRIx32" not %d-byte aligned"),
128
0
            chunk_id, expected_alignment);
129
0
      return 1;
130
0
    }
131
132
0
    table_of_contents += CHUNK_TOC_ENTRY_SIZE;
133
0
    next_chunk_offset = get_be64(table_of_contents + 4);
134
135
0
    if (next_chunk_offset < chunk_offset ||
136
0
        next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
137
0
      error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
138
0
            chunk_offset, next_chunk_offset);
139
0
      return -1;
140
0
    }
141
142
0
    for (i = 0; i < cf->chunks_nr; i++) {
143
0
      if (cf->chunks[i].id == chunk_id) {
144
0
        error(_("duplicate chunk ID %"PRIx32" found"),
145
0
          chunk_id);
146
0
        return -1;
147
0
      }
148
0
    }
149
150
0
    cf->chunks[cf->chunks_nr].id = chunk_id;
151
0
    cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
152
0
    cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
153
0
    cf->chunks_nr++;
154
0
  }
155
156
0
  chunk_id = get_be32(table_of_contents);
157
0
  if (chunk_id) {
158
0
    error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
159
0
    return -1;
160
0
  }
161
162
0
  return 0;
163
0
}
164
165
struct pair_chunk_data {
166
  const unsigned char **p;
167
  size_t *size;
168
};
169
170
static int pair_chunk_fn(const unsigned char *chunk_start,
171
       size_t chunk_size,
172
       void *data)
173
0
{
174
0
  struct pair_chunk_data *pcd = data;
175
0
  *pcd->p = chunk_start;
176
0
  *pcd->size = chunk_size;
177
0
  return 0;
178
0
}
179
180
int pair_chunk(struct chunkfile *cf,
181
         uint32_t chunk_id,
182
         const unsigned char **p,
183
         size_t *size)
184
0
{
185
0
  struct pair_chunk_data pcd = { .p = p, .size = size };
186
0
  return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
187
0
}
188
189
int read_chunk(struct chunkfile *cf,
190
         uint32_t chunk_id,
191
         chunk_read_fn fn,
192
         void *data)
193
0
{
194
0
  int i;
195
196
0
  for (i = 0; i < cf->chunks_nr; i++) {
197
0
    if (cf->chunks[i].id == chunk_id)
198
0
      return fn(cf->chunks[i].start, cf->chunks[i].size, data);
199
0
  }
200
201
0
  return CHUNK_NOT_FOUND;
202
0
}
203
204
uint8_t oid_version(const struct git_hash_algo *algop)
205
0
{
206
0
  switch (hash_algo_by_ptr(algop)) {
207
0
  case GIT_HASH_SHA1:
208
0
    return 1;
209
0
  case GIT_HASH_SHA256:
210
0
    return 2;
211
0
  default:
212
0
    die(_("invalid hash version"));
213
0
  }
214
0
}