mirror of
https://github.com/git/git
synced 2024-08-27 11:39:22 +00:00
![Jeff King](/assets/img/avatar_default.png)
Many functions which handle refs use a PATH_MAX-sized buffer to do so. This is mostly reasonable as we have to write loose refs into the filesystem, and at least on Linux the 4K PATH_MAX is big enough that nobody would care. But: 1. The static PATH_MAX is not always the filesystem limit. 2. On other platforms, PATH_MAX may be much smaller. 3. As we move to alternate ref storage, we won't be bound by filesystem limits. Let's convert these to heap buffers so we don't have to worry about truncation or size limits. We may want to eventually constrain ref lengths for sanity and to prevent malicious names, but we should do so consistently across all platforms, and in a central place (like the ref code). Signed-off-by: Jeff King <peff@peff.net>
117 lines
3.1 KiB
C
117 lines
3.1 KiB
C
#include "builtin.h"
|
|
#include "cache.h"
|
|
#include "transport.h"
|
|
#include "remote.h"
|
|
|
|
static const char * const ls_remote_usage[] = {
|
|
N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
|
|
" [-q | --quiet] [--exit-code] [--get-url]\n"
|
|
" [--symref] [<repository> [<refs>...]]"),
|
|
NULL
|
|
};
|
|
|
|
/*
|
|
* Is there one among the list of patterns that match the tail part
|
|
* of the path?
|
|
*/
|
|
static int tail_match(const char **pattern, const char *path)
|
|
{
|
|
const char *p;
|
|
char *pathbuf;
|
|
|
|
if (!pattern)
|
|
return 1; /* no restriction */
|
|
|
|
pathbuf = xstrfmt("/%s", path);
|
|
while ((p = *(pattern++)) != NULL) {
|
|
if (!wildmatch(p, pathbuf, 0, NULL)) {
|
|
free(pathbuf);
|
|
return 1;
|
|
}
|
|
}
|
|
free(pathbuf);
|
|
return 0;
|
|
}
|
|
|
|
int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
|
{
|
|
const char *dest = NULL;
|
|
unsigned flags = 0;
|
|
int get_url = 0;
|
|
int quiet = 0;
|
|
int status = 0;
|
|
int show_symref_target = 0;
|
|
const char *uploadpack = NULL;
|
|
const char **pattern = NULL;
|
|
|
|
struct remote *remote;
|
|
struct transport *transport;
|
|
const struct ref *ref;
|
|
|
|
struct option options[] = {
|
|
OPT__QUIET(&quiet, N_("do not print remote URL")),
|
|
OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"),
|
|
N_("path of git-upload-pack on the remote host")),
|
|
{ OPTION_STRING, 0, "exec", &uploadpack, N_("exec"),
|
|
N_("path of git-upload-pack on the remote host"),
|
|
PARSE_OPT_HIDDEN },
|
|
OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
|
|
OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS),
|
|
OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
|
|
OPT_BOOL(0, "get-url", &get_url,
|
|
N_("take url.<base>.insteadOf into account")),
|
|
OPT_SET_INT(0, "exit-code", &status,
|
|
N_("exit with exit code 2 if no matching refs are found"), 2),
|
|
OPT_BOOL(0, "symref", &show_symref_target,
|
|
N_("show underlying ref in addition to the object pointed by it")),
|
|
OPT_END()
|
|
};
|
|
|
|
argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
|
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
|
dest = argv[0];
|
|
|
|
if (argc > 1) {
|
|
int i;
|
|
pattern = xcalloc(argc, sizeof(const char *));
|
|
for (i = 1; i < argc; i++)
|
|
pattern[i - 1] = xstrfmt("*/%s", argv[i]);
|
|
}
|
|
|
|
remote = remote_get(dest);
|
|
if (!remote) {
|
|
if (dest)
|
|
die("bad repository '%s'", dest);
|
|
die("No remote configured to list refs from.");
|
|
}
|
|
if (!remote->url_nr)
|
|
die("remote %s has no configured URL", dest);
|
|
|
|
if (get_url) {
|
|
printf("%s\n", *remote->url);
|
|
return 0;
|
|
}
|
|
|
|
transport = transport_get(remote, NULL);
|
|
if (uploadpack != NULL)
|
|
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
|
|
|
|
ref = transport_get_remote_refs(transport);
|
|
if (transport_disconnect(transport))
|
|
return 1;
|
|
|
|
if (!dest && !quiet)
|
|
fprintf(stderr, "From %s\n", *remote->url);
|
|
for ( ; ref; ref = ref->next) {
|
|
if (!check_ref_type(ref, flags))
|
|
continue;
|
|
if (!tail_match(pattern, ref->name))
|
|
continue;
|
|
if (show_symref_target && ref->symref)
|
|
printf("ref: %s\t%s\n", ref->symref, ref->name);
|
|
printf("%s\t%s\n", oid_to_hex(&ref->old_oid), ref->name);
|
|
status = 0; /* we found something */
|
|
}
|
|
return status;
|
|
}
|