Coverage Report

Created: 2026-03-31 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/odb/source-files.c
Line
Count
Source
1
#include "git-compat-util.h"
2
#include "abspath.h"
3
#include "chdir-notify.h"
4
#include "gettext.h"
5
#include "lockfile.h"
6
#include "object-file.h"
7
#include "odb.h"
8
#include "odb/source.h"
9
#include "odb/source-files.h"
10
#include "packfile.h"
11
#include "strbuf.h"
12
#include "write-or-die.h"
13
14
static void odb_source_files_reparent(const char *name UNUSED,
15
              const char *old_cwd,
16
              const char *new_cwd,
17
              void *cb_data)
18
0
{
19
0
  struct odb_source_files *files = cb_data;
20
0
  char *path = reparent_relative_path(old_cwd, new_cwd,
21
0
              files->base.path);
22
0
  free(files->base.path);
23
0
  files->base.path = path;
24
0
}
25
26
static void odb_source_files_free(struct odb_source *source)
27
0
{
28
0
  struct odb_source_files *files = odb_source_files_downcast(source);
29
0
  chdir_notify_unregister(NULL, odb_source_files_reparent, files);
30
0
  odb_source_loose_free(files->loose);
31
0
  packfile_store_free(files->packed);
32
0
  odb_source_release(&files->base);
33
0
  free(files);
34
0
}
35
36
static void odb_source_files_close(struct odb_source *source)
37
0
{
38
0
  struct odb_source_files *files = odb_source_files_downcast(source);
39
0
  packfile_store_close(files->packed);
40
0
}
41
42
static void odb_source_files_reprepare(struct odb_source *source)
43
0
{
44
0
  struct odb_source_files *files = odb_source_files_downcast(source);
45
0
  odb_source_loose_reprepare(&files->base);
46
0
  packfile_store_reprepare(files->packed);
47
0
}
48
49
static int odb_source_files_read_object_info(struct odb_source *source,
50
               const struct object_id *oid,
51
               struct object_info *oi,
52
               enum object_info_flags flags)
53
0
{
54
0
  struct odb_source_files *files = odb_source_files_downcast(source);
55
56
0
  if (!packfile_store_read_object_info(files->packed, oid, oi, flags) ||
57
0
      !odb_source_loose_read_object_info(source, oid, oi, flags))
58
0
    return 0;
59
60
0
  return -1;
61
0
}
62
63
static int odb_source_files_read_object_stream(struct odb_read_stream **out,
64
                 struct odb_source *source,
65
                 const struct object_id *oid)
66
0
{
67
0
  struct odb_source_files *files = odb_source_files_downcast(source);
68
0
  if (!packfile_store_read_object_stream(out, files->packed, oid) ||
69
0
      !odb_source_loose_read_object_stream(out, source, oid))
70
0
    return 0;
71
0
  return -1;
72
0
}
73
74
static int odb_source_files_for_each_object(struct odb_source *source,
75
              const struct object_info *request,
76
              odb_for_each_object_cb cb,
77
              void *cb_data,
78
              unsigned flags)
79
0
{
80
0
  struct odb_source_files *files = odb_source_files_downcast(source);
81
0
  int ret;
82
83
0
  if (!(flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
84
0
    ret = odb_source_loose_for_each_object(source, request, cb, cb_data, flags);
85
0
    if (ret)
86
0
      return ret;
87
0
  }
88
89
0
  ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, flags);
90
0
  if (ret)
91
0
    return ret;
92
93
0
  return 0;
94
0
}
95
96
static int odb_source_files_count_objects(struct odb_source *source,
97
            enum odb_count_objects_flags flags,
98
            unsigned long *out)
99
0
{
100
0
  struct odb_source_files *files = odb_source_files_downcast(source);
101
0
  unsigned long count;
102
0
  int ret;
103
104
0
  ret = packfile_store_count_objects(files->packed, flags, &count);
105
0
  if (ret < 0)
106
0
    goto out;
107
108
0
  if (!(flags & ODB_COUNT_OBJECTS_APPROXIMATE)) {
109
0
    unsigned long loose_count;
110
111
0
    ret = odb_source_loose_count_objects(source, flags, &loose_count);
112
0
    if (ret < 0)
113
0
      goto out;
114
115
0
    count += loose_count;
116
0
  }
117
118
0
  *out = count;
119
0
  ret = 0;
120
121
0
out:
122
0
  return ret;
123
0
}
124
125
static int odb_source_files_freshen_object(struct odb_source *source,
126
             const struct object_id *oid)
127
0
{
128
0
  struct odb_source_files *files = odb_source_files_downcast(source);
129
0
  if (packfile_store_freshen_object(files->packed, oid) ||
130
0
      odb_source_loose_freshen_object(source, oid))
131
0
    return 1;
132
0
  return 0;
133
0
}
134
135
static int odb_source_files_write_object(struct odb_source *source,
136
           const void *buf, unsigned long len,
137
           enum object_type type,
138
           struct object_id *oid,
139
           struct object_id *compat_oid,
140
           unsigned flags)
141
0
{
142
0
  return odb_source_loose_write_object(source, buf, len, type,
143
0
               oid, compat_oid, flags);
144
0
}
145
146
static int odb_source_files_write_object_stream(struct odb_source *source,
147
            struct odb_write_stream *stream,
148
            size_t len,
149
            struct object_id *oid)
150
0
{
151
0
  return odb_source_loose_write_stream(source, stream, len, oid);
152
0
}
153
154
static int odb_source_files_begin_transaction(struct odb_source *source,
155
                struct odb_transaction **out)
156
0
{
157
0
  struct odb_transaction *tx = odb_transaction_files_begin(source);
158
0
  if (!tx)
159
0
    return -1;
160
0
  *out = tx;
161
0
  return 0;
162
0
}
163
164
static int odb_source_files_read_alternates(struct odb_source *source,
165
              struct strvec *out)
166
0
{
167
0
  struct strbuf buf = STRBUF_INIT;
168
0
  char *path;
169
170
0
  path = xstrfmt("%s/info/alternates", source->path);
171
0
  if (strbuf_read_file(&buf, path, 1024) < 0) {
172
0
    warn_on_fopen_errors(path);
173
0
    free(path);
174
0
    return 0;
175
0
  }
176
0
  parse_alternates(buf.buf, '\n', source->path, out);
177
178
0
  strbuf_release(&buf);
179
0
  free(path);
180
0
  return 0;
181
0
}
182
183
static int odb_source_files_write_alternate(struct odb_source *source,
184
              const char *alternate)
185
0
{
186
0
  struct lock_file lock = LOCK_INIT;
187
0
  char *path = xstrfmt("%s/%s", source->path, "info/alternates");
188
0
  FILE *in, *out;
189
0
  int found = 0;
190
0
  int ret;
191
192
0
  hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
193
0
  out = fdopen_lock_file(&lock, "w");
194
0
  if (!out) {
195
0
    ret = error_errno(_("unable to fdopen alternates lockfile"));
196
0
    goto out;
197
0
  }
198
199
0
  in = fopen(path, "r");
200
0
  if (in) {
201
0
    struct strbuf line = STRBUF_INIT;
202
203
0
    while (strbuf_getline(&line, in) != EOF) {
204
0
      if (!strcmp(alternate, line.buf)) {
205
0
        found = 1;
206
0
        break;
207
0
      }
208
0
      fprintf_or_die(out, "%s\n", line.buf);
209
0
    }
210
211
0
    strbuf_release(&line);
212
0
    fclose(in);
213
0
  } else if (errno != ENOENT) {
214
0
    ret = error_errno(_("unable to read alternates file"));
215
0
    goto out;
216
0
  }
217
218
0
  if (found) {
219
0
    rollback_lock_file(&lock);
220
0
  } else {
221
0
    fprintf_or_die(out, "%s\n", alternate);
222
0
    if (commit_lock_file(&lock)) {
223
0
      ret = error_errno(_("unable to move new alternates file into place"));
224
0
      goto out;
225
0
    }
226
0
  }
227
228
0
  ret = 0;
229
230
0
out:
231
0
  free(path);
232
0
  return ret;
233
0
}
234
235
struct odb_source_files *odb_source_files_new(struct object_database *odb,
236
                const char *path,
237
                bool local)
238
0
{
239
0
  struct odb_source_files *files;
240
241
0
  CALLOC_ARRAY(files, 1);
242
0
  odb_source_init(&files->base, odb, ODB_SOURCE_FILES, path, local);
243
0
  files->loose = odb_source_loose_new(&files->base);
244
0
  files->packed = packfile_store_new(&files->base);
245
246
0
  files->base.free = odb_source_files_free;
247
0
  files->base.close = odb_source_files_close;
248
0
  files->base.reprepare = odb_source_files_reprepare;
249
0
  files->base.read_object_info = odb_source_files_read_object_info;
250
0
  files->base.read_object_stream = odb_source_files_read_object_stream;
251
0
  files->base.for_each_object = odb_source_files_for_each_object;
252
0
  files->base.count_objects = odb_source_files_count_objects;
253
0
  files->base.freshen_object = odb_source_files_freshen_object;
254
0
  files->base.write_object = odb_source_files_write_object;
255
0
  files->base.write_object_stream = odb_source_files_write_object_stream;
256
0
  files->base.begin_transaction = odb_source_files_begin_transaction;
257
0
  files->base.read_alternates = odb_source_files_read_alternates;
258
0
  files->base.write_alternate = odb_source_files_write_alternate;
259
260
  /*
261
   * Ideally, we would only ever store absolute paths in the source. This
262
   * is not (yet) possible though because we access and assume relative
263
   * paths in the primary ODB source in some user-facing functionality.
264
   */
265
0
  if (!is_absolute_path(path))
266
0
    chdir_notify_register(NULL, odb_source_files_reparent, files);
267
268
0
  return files;
269
0
}