Enhance filter_refs (which decides whether a request for an unadvertised
object should be sent to the server) to record a new match status on the
"struct ref" when a request is not allowed, and have
report_unmatched_refs check for this status and print a special error
message, "Server does not allow request for unadvertised object".

Signed-off-by: Matt McCutchen <m...@mattmccutchen.net>
---
 fetch-pack.c          | 42 +++++++++++++++++++++++++++---------------
 remote.h              |  9 +++++++--
 t/t5516-fetch-push.sh |  2 +-
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/fetch-pack.c b/fetch-pack.c
index 7c8d44c..f12bfcd 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -578,7 +578,7 @@ static void filter_refs(struct fetch_pack_args *args,
                                        break; /* definitely do not have it */
                                else if (cmp == 0) {
                                        keep = 1; /* definitely have it */
-                                       sought[i]->matched = 1;
+                                       sought[i]->match_status = REF_MATCHED;
                                }
                                i++;
                        }
@@ -598,22 +598,24 @@ static void filter_refs(struct fetch_pack_args *args,
        }
 
        /* Append unmatched requests to the list */
-       if ((allow_unadvertised_object_request &
-           (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
-               for (i = 0; i < nr_sought; i++) {
-                       unsigned char sha1[20];
+       for (i = 0; i < nr_sought; i++) {
+               unsigned char sha1[20];
 
-                       ref = sought[i];
-                       if (ref->matched)
-                               continue;
-                       if (get_sha1_hex(ref->name, sha1) ||
-                           ref->name[40] != '\0' ||
-                           hashcmp(sha1, ref->old_oid.hash))
-                               continue;
+               ref = sought[i];
+               if (ref->match_status != REF_NOT_MATCHED)
+                       continue;
+               if (get_sha1_hex(ref->name, sha1) ||
+                   ref->name[40] != '\0' ||
+                   hashcmp(sha1, ref->old_oid.hash))
+                       continue;
 
-                       ref->matched = 1;
+               if ((allow_unadvertised_object_request &
+                   (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
+                       ref->match_status = REF_MATCHED;
                        *newtail = copy_ref(ref);
                        newtail = &(*newtail)->next;
+               } else {
+                       ref->match_status = REF_UNADVERTISED_NOT_ALLOWED;
                }
        }
        *refs = newlist;
@@ -1100,9 +1102,19 @@ int report_unmatched_refs(struct ref **sought, int 
nr_sought)
        int i, ret = 0;
 
        for (i = 0; i < nr_sought; i++) {
-               if (!sought[i] || sought[i]->matched)
+               if (!sought[i])
                        continue;
-               error(_("no such remote ref %s"), sought[i]->name);
+               switch (sought[i]->match_status) {
+               case REF_MATCHED:
+                       continue;
+               case REF_NOT_MATCHED:
+                       error(_("no such remote ref %s"), sought[i]->name);
+                       break;
+               case REF_UNADVERTISED_NOT_ALLOWED:
+                       error(_("Server does not allow request for unadvertised 
object %s"),
+                             sought[i]->name);
+                       break;
+               }
                ret = 1;
        }
        return ret;
diff --git a/remote.h b/remote.h
index 9248811..0b9d8c4 100644
--- a/remote.h
+++ b/remote.h
@@ -89,8 +89,13 @@ struct ref {
                force:1,
                forced_update:1,
                expect_old_sha1:1,
-               deletion:1,
-               matched:1;
+               deletion:1;
+
+       enum {
+               REF_NOT_MATCHED = 0, /* initial value */
+               REF_MATCHED,
+               REF_UNADVERTISED_NOT_ALLOWED
+       } match_status;
 
        /*
         * Order is important here, as we write to FETCH_HEAD
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0d13a45..78f3b8e 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1099,7 +1099,7 @@ test_expect_success 'fetch exact SHA1' '
 
                # fetching the hidden object should fail by default
                test_must_fail git fetch -v ../testrepo 
$the_commit:refs/heads/copy 2>err &&
-               test_i18ngrep "no such remote ref" err &&
+               test_i18ngrep "Server does not allow request for unadvertised 
object" err &&
                test_must_fail git rev-parse --verify refs/heads/copy &&
 
                # the server side can allow it to succeed
-- 
2.9.3


Reply via email to