]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'rs/apply-symlinks-use-strset'
authorJunio C Hamano <gitster@pobox.com>
Sat, 5 Feb 2022 17:42:30 +0000 (09:42 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 5 Feb 2022 17:42:30 +0000 (09:42 -0800)
"git apply" (ab)used the util pointer of the string-list to keep
track of how each symbolic link needs to be handled, which has been
simplified by using strset.

* rs/apply-symlinks-use-strset:
  apply: use strsets to track symlinks

1  2 
apply.c
apply.h

diff --combined apply.c
index 7ffadc3b17a314095e213ad31ceda83a9915afb2,99f76b59378851042ac87edf03b354dfeb6a551c..f66d48ba2f3070822fa9f78bd6d90e41427bc075
+++ b/apply.c
@@@ -103,7 -103,8 +103,8 @@@ int init_apply_state(struct apply_stat
        state->linenr = 1;
        string_list_init_nodup(&state->fn_table);
        string_list_init_nodup(&state->limit_by_name);
-       string_list_init_nodup(&state->symlink_changes);
+       strset_init(&state->removed_symlinks);
+       strset_init(&state->kept_symlinks);
        strbuf_init(&state->root, 0);
  
        git_apply_config();
  void clear_apply_state(struct apply_state *state)
  {
        string_list_clear(&state->limit_by_name, 0);
-       string_list_clear(&state->symlink_changes, 0);
+       strset_clear(&state->removed_symlinks);
+       strset_clear(&state->kept_symlinks);
        strbuf_release(&state->root);
  
        /* &state->fn_table is cleared at the end of apply_patch() */
@@@ -133,10 -135,10 +135,10 @@@ int check_apply_state(struct apply_stat
        int is_not_gitdir = !startup_info->have_repository;
  
        if (state->apply_with_reject && state->threeway)
 -              return error(_("--reject and --3way cannot be used together."));
 +              return error(_("options '%s' and '%s' cannot be used together"), "--reject", "--3way");
        if (state->threeway) {
                if (is_not_gitdir)
 -                      return error(_("--3way outside a repository"));
 +                      return error(_("'%s' outside a repository"), "--3way");
                state->check_index = 1;
        }
        if (state->apply_with_reject) {
        if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
                state->apply = 0;
        if (state->check_index && is_not_gitdir)
 -              return error(_("--index outside a repository"));
 +              return error(_("'%s' outside a repository"), "--index");
        if (state->cached) {
                if (is_not_gitdir)
 -                      return error(_("--cached outside a repository"));
 +                      return error(_("'%s' outside a repository"), "--cached");
                state->check_index = 1;
        }
        if (state->ita_only && (state->check_index || is_not_gitdir))
@@@ -3582,9 -3584,7 +3584,9 @@@ static int try_threeway(struct apply_st
  
        /* No point falling back to 3-way merge in these cases */
        if (patch->is_delete ||
 -          S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
 +          S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode) ||
 +          (patch->is_new && !patch->direct_to_threeway) ||
 +          (patch->is_rename && !patch->lines_added && !patch->lines_deleted))
                return -1;
  
        /* Preimage the patch was prepared for */
@@@ -3814,59 -3814,31 +3816,31 @@@ static int check_to_create(struct apply
        return 0;
  }
  
- static uintptr_t register_symlink_changes(struct apply_state *state,
-                                         const char *path,
-                                         uintptr_t what)
- {
-       struct string_list_item *ent;
-       ent = string_list_lookup(&state->symlink_changes, path);
-       if (!ent) {
-               ent = string_list_insert(&state->symlink_changes, path);
-               ent->util = (void *)0;
-       }
-       ent->util = (void *)(what | ((uintptr_t)ent->util));
-       return (uintptr_t)ent->util;
- }
- static uintptr_t check_symlink_changes(struct apply_state *state, const char *path)
- {
-       struct string_list_item *ent;
-       ent = string_list_lookup(&state->symlink_changes, path);
-       if (!ent)
-               return 0;
-       return (uintptr_t)ent->util;
- }
  static void prepare_symlink_changes(struct apply_state *state, struct patch *patch)
  {
        for ( ; patch; patch = patch->next) {
                if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
                    (patch->is_rename || patch->is_delete))
                        /* the symlink at patch->old_name is removed */
-                       register_symlink_changes(state, patch->old_name, APPLY_SYMLINK_GOES_AWAY);
+                       strset_add(&state->removed_symlinks, patch->old_name);
  
                if (patch->new_name && S_ISLNK(patch->new_mode))
                        /* the symlink at patch->new_name is created or remains */
-                       register_symlink_changes(state, patch->new_name, APPLY_SYMLINK_IN_RESULT);
+                       strset_add(&state->kept_symlinks, patch->new_name);
        }
  }
  
  static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *name)
  {
        do {
-               unsigned int change;
                while (--name->len && name->buf[name->len] != '/')
                        ; /* scan backwards */
                if (!name->len)
                        break;
                name->buf[name->len] = '\0';
-               change = check_symlink_changes(state, name->buf);
-               if (change & APPLY_SYMLINK_IN_RESULT)
+               if (strset_contains(&state->kept_symlinks, name->buf))
                        return 1;
-               if (change & APPLY_SYMLINK_GOES_AWAY)
+               if (strset_contains(&state->removed_symlinks, name->buf))
                        /*
                         * This cannot be "return 0", because we may
                         * see a new one created at a higher level.
@@@ -4754,10 -4726,8 +4728,10 @@@ static int apply_patch(struct apply_sta
        }
  
        if (!list && !skipped_patch) {
 -              error(_("unrecognized input"));
 -              res = -128;
 +              if (!state->allow_empty) {
 +                      error(_("No valid patches in input (allow with \"--allow-empty\")"));
 +                      res = -128;
 +              }
                goto end;
        }
  
@@@ -5075,7 -5045,7 +5049,7 @@@ int apply_parse_options(int argc, cons
                        N_("leave the rejected hunks in corresponding *.rej files")),
                OPT_BOOL(0, "allow-overlap", &state->allow_overlap,
                        N_("allow overlapping hunks")),
 -              OPT__VERBOSE(&state->apply_verbosity, N_("be verbose")),
 +              OPT__VERBOSITY(&state->apply_verbosity),
                OPT_BIT(0, "inaccurate-eof", options,
                        N_("tolerate incorrectly detected missing new-line at the end of file"),
                        APPLY_OPT_INACCURATE_EOF),
                OPT_CALLBACK(0, "directory", state, N_("root"),
                        N_("prepend <root> to all filenames"),
                        apply_option_parse_directory),
 +              OPT_BOOL(0, "allow-empty", &state->allow_empty,
 +                      N_("don't return error for empty patches")),
                OPT_END()
        };
  
diff --combined apply.h
index 16202da16026f8ef127e406418229d1f47802b53,1f959c064e305a5686a95726f264d147a49c20fe..4052da50c0658cf6434b262bba6f557459e7950c
+++ b/apply.h
@@@ -4,6 -4,7 +4,7 @@@
  #include "hash.h"
  #include "lockfile.h"
  #include "string-list.h"
+ #include "strmap.h"
  
  struct repository;
  
@@@ -25,20 -26,6 +26,6 @@@ enum apply_verbosity 
        verbosity_verbose = 1
  };
  
- /*
-  * We need to keep track of how symlinks in the preimage are
-  * manipulated by the patches.  A patch to add a/b/c where a/b
-  * is a symlink should not be allowed to affect the directory
-  * the symlink points at, but if the same patch removes a/b,
-  * it is perfectly fine, as the patch removes a/b to make room
-  * to create a directory a/b so that a/b/c can be created.
-  *
-  * See also "struct string_list symlink_changes" in "struct
-  * apply_state".
-  */
- #define APPLY_SYMLINK_GOES_AWAY 01
- #define APPLY_SYMLINK_IN_RESULT 02
  struct apply_state {
        const char *prefix;
  
@@@ -66,7 -53,6 +53,7 @@@
        int threeway;
        int unidiff_zero;
        int unsafe_paths;
 +      int allow_empty;
  
        /* Other non boolean parameters */
        struct repository *repo;
  
        /* Various "current state" */
        int linenr; /* current line number */
-       struct string_list symlink_changes; /* we have to track symlinks */
+       /*
+        * We need to keep track of how symlinks in the preimage are
+        * manipulated by the patches.  A patch to add a/b/c where a/b
+        * is a symlink should not be allowed to affect the directory
+        * the symlink points at, but if the same patch removes a/b,
+        * it is perfectly fine, as the patch removes a/b to make room
+        * to create a directory a/b so that a/b/c can be created.
+        */
+       struct strset removed_symlinks;
+       struct strset kept_symlinks;
  
        /*
         * For "diff-stat" like behaviour, we keep track of the biggest change