multi-pack-index: use --object-dir real path

The --object-dir argument to 'git multi-pack-index' allows a user to specify an alternate to use instead of the local $GITDIR. This is used by third-party tools like VFS for Git to maintain the pack-files in a "shared object cache" used by multiple clones. On Windows, the user can specify a path using a Windows-style file path with backslashes such as "C:\Path\To\ObjectDir". This same path style is used in the .git/objects/info/alternates file, so it already matches the path of that alternate. However, find_odb() converts these paths to real-paths for the comparison, which use forward slashes. As of the previous change, lookup_multi_pack_index() uses real-paths, so it correctly finds the target multi-pack-index when given these paths. Some commands such as 'git multi-pack-index repack' call child processes using the object_dir value, so it can be helpful to convert the path to the real-path before sending it to those locations. Add a callback to convert the real path immediately upon parsing the argument. We need to be careful that we don't store the exact value out of get_object_directory() and free it, or we could corrupt a later use of the_repository->objects->odb->path. We don't use get_object_directory() for the initial instantiation in cmd_multi_pack_index() because we need 'git multi-pack-index -h' to work without a Git repository. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Apr 25, 2022 at 18:27 UTC b56166ca57678795b4159b6a48b64fbacb93e73d
1 file changed +34 -11
builtin/multi-pack-index.c
+34 -11
@@ -44,7 +44,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
44 };
45
46 static struct opts_multi_pack_index {
47 - const char *object_dir;
47 + char *object_dir;
48 const char *preferred_pack;
49 const char *refs_snapshot;
50 unsigned long batch_size;
@@ -52,9 +52,23 @@ static struct opts_multi_pack_index {
52 int stdin_packs;
53 } opts;
54
55 +
56 +static int parse_object_dir(const struct option *opt, const char *arg,
57 + int unset)
58 +{
59 + free(opts.object_dir);
60 + if (unset)
61 + opts.object_dir = xstrdup(get_object_directory());
62 + else
63 + opts.object_dir = real_pathdup(arg, 1);
64 + return 0;
65 +}
66 +
67 static struct option common_opts[] = {
56 - OPT_FILENAME(0, "object-dir", &opts.object_dir,
57 - N_("object directory containing set of packfile and pack-index pairs")),
68 + OPT_CALLBACK(0, "object-dir", &opts.object_dir,
69 + N_("directory"),
70 + N_("object directory containing set of packfile and pack-index pairs"),
71 + parse_object_dir),
72 OPT_END(),
73 };
74
@@ -232,31 +246,40 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv)
246 int cmd_multi_pack_index(int argc, const char **argv,
247 const char *prefix)
248 {
249 + int res;
250 struct option *builtin_multi_pack_index_options = common_opts;
251
252 git_config(git_default_config, NULL);
253
254 + if (the_repository &&
255 + the_repository->objects &&
256 + the_repository->objects->odb)
257 + opts.object_dir = xstrdup(the_repository->objects->odb->path);
258 +
259 argc = parse_options(argc, argv, prefix,
260 builtin_multi_pack_index_options,
261 builtin_multi_pack_index_usage,
262 PARSE_OPT_STOP_AT_NON_OPTION);
263
244 - if (!opts.object_dir)
245 - opts.object_dir = get_object_directory();
246 -
264 if (!argc)
265 goto usage;
266
267 if (!strcmp(argv[0], "repack"))
251 - return cmd_multi_pack_index_repack(argc, argv);
268 + res = cmd_multi_pack_index_repack(argc, argv);
269 else if (!strcmp(argv[0], "write"))
253 - return cmd_multi_pack_index_write(argc, argv);
270 + res = cmd_multi_pack_index_write(argc, argv);
271 else if (!strcmp(argv[0], "verify"))
255 - return cmd_multi_pack_index_verify(argc, argv);
272 + res = cmd_multi_pack_index_verify(argc, argv);
273 else if (!strcmp(argv[0], "expire"))
257 - return cmd_multi_pack_index_expire(argc, argv);
274 + res = cmd_multi_pack_index_expire(argc, argv);
275 + else {
276 + error(_("unrecognized subcommand: %s"), argv[0]);
277 + goto usage;
278 + }
279 +
280 + free(opts.object_dir);
281 + return res;
282
259 - error(_("unrecognized subcommand: %s"), argv[0]);
283 usage:
284 usage_with_options(builtin_multi_pack_index_usage,
285 builtin_multi_pack_index_options);