Coverage Report

Created: 2026-03-21 06:46

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_freshen_object(struct odb_source *source,
97
             const struct object_id *oid)
98
0
{
99
0
  struct odb_source_files *files = odb_source_files_downcast(source);
100
0
  if (packfile_store_freshen_object(files->packed, oid) ||
101
0
      odb_source_loose_freshen_object(source, oid))
102
0
    return 1;
103
0
  return 0;
104
0
}
105
106
static int odb_source_files_write_object(struct odb_source *source,
107
           const void *buf, unsigned long len,
108
           enum object_type type,
109
           struct object_id *oid,
110
           struct object_id *compat_oid,
111
           unsigned flags)
112
0
{
113
0
  return odb_source_loose_write_object(source, buf, len, type,
114
0
               oid, compat_oid, flags);
115
0
}
116
117
static int odb_source_files_write_object_stream(struct odb_source *source,
118
            struct odb_write_stream *stream,
119
            size_t len,
120
            struct object_id *oid)
121
0
{
122
0
  return odb_source_loose_write_stream(source, stream, len, oid);
123
0
}
124
125
static int odb_source_files_begin_transaction(struct odb_source *source,
126
                struct odb_transaction **out)
127
0
{
128
0
  struct odb_transaction *tx = odb_transaction_files_begin(source);
129
0
  if (!tx)
130
0
    return -1;
131
0
  *out = tx;
132
0
  return 0;
133
0
}
134
135
static int odb_source_files_read_alternates(struct odb_source *source,
136
              struct strvec *out)
137
0
{
138
0
  struct strbuf buf = STRBUF_INIT;
139
0
  char *path;
140
141
0
  path = xstrfmt("%s/info/alternates", source->path);
142
0
  if (strbuf_read_file(&buf, path, 1024) < 0) {
143
0
    warn_on_fopen_errors(path);
144
0
    free(path);
145
0
    return 0;
146
0
  }
147
0
  parse_alternates(buf.buf, '\n', source->path, out);
148
149
0
  strbuf_release(&buf);
150
0
  free(path);
151
0
  return 0;
152
0
}
153
154
static int odb_source_files_write_alternate(struct odb_source *source,
155
              const char *alternate)
156
0
{
157
0
  struct lock_file lock = LOCK_INIT;
158
0
  char *path = xstrfmt("%s/%s", source->path, "info/alternates");
159
0
  FILE *in, *out;
160
0
  int found = 0;
161
0
  int ret;
162
163
0
  hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
164
0
  out = fdopen_lock_file(&lock, "w");
165
0
  if (!out) {
166
0
    ret = error_errno(_("unable to fdopen alternates lockfile"));
167
0
    goto out;
168
0
  }
169
170
0
  in = fopen(path, "r");
171
0
  if (in) {
172
0
    struct strbuf line = STRBUF_INIT;
173
174
0
    while (strbuf_getline(&line, in) != EOF) {
175
0
      if (!strcmp(alternate, line.buf)) {
176
0
        found = 1;
177
0
        break;
178
0
      }
179
0
      fprintf_or_die(out, "%s\n", line.buf);
180
0
    }
181
182
0
    strbuf_release(&line);
183
0
    fclose(in);
184
0
  } else if (errno != ENOENT) {
185
0
    ret = error_errno(_("unable to read alternates file"));
186
0
    goto out;
187
0
  }
188
189
0
  if (found) {
190
0
    rollback_lock_file(&lock);
191
0
  } else {
192
0
    fprintf_or_die(out, "%s\n", alternate);
193
0
    if (commit_lock_file(&lock)) {
194
0
      ret = error_errno(_("unable to move new alternates file into place"));
195
0
      goto out;
196
0
    }
197
0
  }
198
199
0
  ret = 0;
200
201
0
out:
202
0
  free(path);
203
0
  return ret;
204
0
}
205
206
struct odb_source_files *odb_source_files_new(struct object_database *odb,
207
                const char *path,
208
                bool local)
209
0
{
210
0
  struct odb_source_files *files;
211
212
0
  CALLOC_ARRAY(files, 1);
213
0
  odb_source_init(&files->base, odb, ODB_SOURCE_FILES, path, local);
214
0
  files->loose = odb_source_loose_new(&files->base);
215
0
  files->packed = packfile_store_new(&files->base);
216
217
0
  files->base.free = odb_source_files_free;
218
0
  files->base.close = odb_source_files_close;
219
0
  files->base.reprepare = odb_source_files_reprepare;
220
0
  files->base.read_object_info = odb_source_files_read_object_info;
221
0
  files->base.read_object_stream = odb_source_files_read_object_stream;
222
0
  files->base.for_each_object = odb_source_files_for_each_object;
223
0
  files->base.freshen_object = odb_source_files_freshen_object;
224
0
  files->base.write_object = odb_source_files_write_object;
225
0
  files->base.write_object_stream = odb_source_files_write_object_stream;
226
0
  files->base.begin_transaction = odb_source_files_begin_transaction;
227
0
  files->base.read_alternates = odb_source_files_read_alternates;
228
0
  files->base.write_alternate = odb_source_files_write_alternate;
229
230
  /*
231
   * Ideally, we would only ever store absolute paths in the source. This
232
   * is not (yet) possible though because we access and assume relative
233
   * paths in the primary ODB source in some user-facing functionality.
234
   */
235
0
  if (!is_absolute_path(path))
236
0
    chdir_notify_register(NULL, odb_source_files_reparent, files);
237
238
0
  return files;
239
0
}