#include "git-compat-util.h"
#include "cache.h"
#include "config.h"
#include "pkt-line.h"
#include "quote.h"
#include "refs.h"
#include "run-command.h"
#include "remote.h"
#include "connect.h"
#include "url.h"
#include "string-list.h"
#include "sha1-array.h"
#include "transport.h"
#include "strbuf.h"
#include "protocol.h"
static char *server_capabilities;
static const char *parse_feature_value(const char *, const char *, int *);
static int check_ref(const char *name, unsigned int flags)
{
if (!flags)
return 1;
if (!skip_prefix(name, "refs/", &name))
return 0;
/* REF_NORMAL means that we don't want the magic fake tag refs */
if ((flags & REF_NORMAL) && check_refname_format(name, 0))
return 0;
/* REF_HEADS means that we want regular branch heads */
if ((flags & REF_HEADS) && starts_with(name, "heads/"))
return 1;
/* REF_TAGS means that we want tags */
if ((flags & REF_TAGS) && starts_with(name, "tags/"))
return 1;
/* All type bits clear means that we are ok with anything */
return !(flags & ~REF_NORMAL);
}
int check_ref_type(const struct ref *ref, int flags)
{
return check_ref(ref->name, flags);
}
static void die_initial_contact(int unexpected)
{
if (unexpected)
die(_("The remote end hung up upon initial contact"));
else
die(_("Could not read from remote repository.\n\n"
"Please make sure you have the correct access rights\n"
"and the repository exists."));
}
static void parse_one_symref_info(struct string_list *symref, const char *val, int len)
{
char *sym, *target;
struct string_list_item *item;
if (!len)
return; /* just "symref" */
/* e.g. "symref=HEAD:refs/heads/master" */
sym = xmemdupz(val, len);
target = strchr(sym, ':');
if (!target)
/* just "symref=something" */
goto reject;
*(target++) = '\0';
if (check_refname_format(sym, REFNAME_ALLOW_ONELEVEL) ||
check_refname_format(target, REFNAME_ALLOW_ONELEVEL))
/* "symref=bogus:pair */
goto reject;
item = string_list_append_nodup(symref, sym);
item->util = target;
return;
reject:
free(sym);
return;
}
static void annotate_refs_with_symref_info(struct ref *ref)
{
struct string_list symref = STRING_LIST_INIT_DUP;
const char *feature_list = server_capabilities;
while (feature_list) {
int len;
const char *val;
val = parse_feature_value(feature_list, "symref", &len);
if (!val)
break;
parse_one_symref_info(&symref, val, len);
feature_list = val + 1;
}
string_list_sort(&symref);
for (; ref; ref = ref->next) {
struct string_list_item *item;
item = string_list_lookup(&symref, ref->name);
if (!item)
continue;
ref->symref = xstrdup((char *)item->util);
}
string_list_clear(&symref, 0);
}
/*
* Read one line of a server's ref advertisement into packet_buffer.
*/
static int read_remote_ref(int in, char **src_buf, size_t *src_len,
int *responded)
{
int len = packet_read(in, src_buf, src_len,
packet_buffer, sizeof(packet_buffer),
PACKET_READ_GENTLE_ON_EOF |
PACKET_READ_CHOMP_NEWLINE);
const char *arg;
if (len < 0)
die_initial_contact(*responded);
if (len > 4 && skip_prefix(packet_buffer, "ERR ", &arg))
die("remote error: %s", arg);
*responded = 1;
return len;
}
#define EXPECTING_PROTOCOL_VERSION 0
#define EXPECTING_FIRST_REF 1
#define EXPECTING_REF 2
#define EXPECTING_SHALLOW 3
/* Returns 1 if packet_buffer is a protocol version pkt-line, 0 otherwise. */
static int process_protocol_version(void)
{
switch (determine_protocol_version_client(packet_buffer)) {
case protocol_v1:
return 1;
case protocol_v0:
return 0;
default:
die("server is speaking an unknown protocol");
}
}
static void process_capabilities(int *len)
{
int nul_location = strlen(packet_buffer);
if (nul_location == *len)
return;
server_capabilities = xstrdup(packet_buffer + nul_location + 1);
*len = nul_location;
}
static int process_dummy_ref(void)
{
|