]> git.ipfire.org Git - thirdparty/git.git/commitdiff
fast-import: fix file access when run from subdir
authorJeff King <peff@peff.net>
Tue, 28 Mar 2023 20:54:13 +0000 (16:54 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 28 Mar 2023 21:11:24 +0000 (14:11 -0700)
In cmd_fast_import(), we ignore the "prefix" argument entirely, even
though it tells us how we may have changed directory to the root of the
repository earlier in the process. Which means that if you run it from a
subdir and point to paths in the filesystem, like:

  cd subdir
  git fast-import --import-marks=foo <dump

then it will look for "foo" in the root of the repository, not the
current directory ("subdir/") which the user would have expected.

We can fix this by recording the prefix and using it as appropriate
whenever we open a file for reading or writing. I found each of these by
looking for cases where we call fopen() within fast-import.c, so this
should cover all cases. The new test triggers each one, as well as
making sure we don't accidentally apply the prefix when --relative-marks
is in use (since that option interprets some paths as relative to a
specific directory).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fast-import.c
t/t9304-fast-import-marks.sh

index f7548ff4a35c081d79af0d895cbf18ca888e2758..19427e05f1cb5b7f035316a7cac13bf031e8e2ae 100644 (file)
@@ -176,6 +176,7 @@ static FILE *pack_edges;
 static unsigned int show_stats = 1;
 static int global_argc;
 static const char **global_argv;
+static const char *global_prefix;
 
 /* Memory pools */
 static struct mem_pool fi_mem_pool = {
@@ -3246,7 +3247,7 @@ static void parse_alias(void)
 static char* make_fast_import_path(const char *path)
 {
        if (!relative_marks_paths || is_absolute_path(path))
-               return xstrdup(path);
+               return prefix_filename(global_prefix, path);
        return git_pathdup("info/fast-import/%s", path);
 }
 
@@ -3317,9 +3318,11 @@ static void option_cat_blob_fd(const char *fd)
 
 static void option_export_pack_edges(const char *edges)
 {
+       char *fn = prefix_filename(global_prefix, edges);
        if (pack_edges)
                fclose(pack_edges);
-       pack_edges = xfopen(edges, "a");
+       pack_edges = xfopen(fn, "a");
+       free(fn);
 }
 
 static void option_rewrite_submodules(const char *arg, struct string_list *list)
@@ -3334,11 +3337,13 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
        f++;
        CALLOC_ARRAY(ms, 1);
 
+       f = prefix_filename(global_prefix, f);
        fp = fopen(f, "r");
        if (!fp)
                die_errno("cannot read '%s'", f);
        read_mark_file(&ms, fp, insert_oid_entry);
        fclose(fp);
+       free(f);
 
        string_list_insert(list, s)->util = ms;
 }
@@ -3552,6 +3557,7 @@ int cmd_fast_import(int argc, const char **argv, const char *prefix)
 
        global_argc = argc;
        global_argv = argv;
+       global_prefix = prefix;
 
        rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
        for (i = 0; i < (cmd_save - 1); i++)
index a98ef032d94c106c8f2ee604b60b771e11880f2d..410a871c52af87cd9fe9ab9da5350b032fc5689d 100755 (executable)
@@ -49,4 +49,33 @@ test_expect_success 'import with submodule mapping' '
        test_cmp expect actual
 '
 
+test_expect_success 'paths adjusted for relative subdir' '
+       git init deep-dst &&
+       mkdir deep-dst/subdir &&
+       >deep-dst/subdir/empty-marks &&
+       git -C deep-dst/subdir fast-import \
+               --rewrite-submodules-from=sub:../../from \
+               --rewrite-submodules-to=sub:../../to \
+               --import-marks=empty-marks \
+               --export-marks=exported-marks \
+               --export-pack-edges=exported-edges \
+               <dump &&
+       # we do not bother checking resulting repo; we just care that nothing
+       # complained about failing to open files for reading, and that files
+       # for writing were created in the expected spot
+       test_path_is_file deep-dst/subdir/exported-marks &&
+       test_path_is_file deep-dst/subdir/exported-edges
+'
+
+test_expect_success 'relative marks are not affected by subdir' '
+       git init deep-relative &&
+       mkdir deep-relative/subdir &&
+       git -C deep-relative/subdir fast-import \
+               --relative-marks \
+               --export-marks=exported-marks \
+               <dump &&
+       test_path_is_missing deep-relative/subdir/exported-marks &&
+       test_path_is_file deep-relative/.git/info/fast-import/exported-marks
+'
+
 test_done