Merge branch 'jc/unseekable-bundle'
* jc/unseekable-bundle: bundle: add parse_bundle_header() helper function bundle: allowing to read from an unseekable fd Conflicts: transport.cmaint
commit
b76c561a74
130
bundle.c
130
bundle.c
|
@ -23,50 +23,102 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name,
|
||||||
list->nr++;
|
list->nr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns an fd */
|
/* Eventually this should go to strbuf.[ch] */
|
||||||
|
static int strbuf_readline_fd(struct strbuf *sb, int fd)
|
||||||
|
{
|
||||||
|
strbuf_reset(sb);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char ch;
|
||||||
|
ssize_t len = xread(fd, &ch, 1);
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
strbuf_addch(sb, ch);
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_bundle_header(int fd, struct bundle_header *header,
|
||||||
|
const char *report_path)
|
||||||
|
{
|
||||||
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
/* The bundle header begins with the signature */
|
||||||
|
if (strbuf_readline_fd(&buf, fd) ||
|
||||||
|
strcmp(buf.buf, bundle_signature)) {
|
||||||
|
if (report_path)
|
||||||
|
error("'%s' does not look like a v2 bundle file",
|
||||||
|
report_path);
|
||||||
|
status = -1;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The bundle header ends with an empty line */
|
||||||
|
while (!strbuf_readline_fd(&buf, fd) &&
|
||||||
|
buf.len && buf.buf[0] != '\n') {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
int is_prereq = 0;
|
||||||
|
|
||||||
|
if (*buf.buf == '-') {
|
||||||
|
is_prereq = 1;
|
||||||
|
strbuf_remove(&buf, 0, 1);
|
||||||
|
}
|
||||||
|
strbuf_rtrim(&buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tip lines have object name, SP, and refname.
|
||||||
|
* Prerequisites have object name that is optionally
|
||||||
|
* followed by SP and subject line.
|
||||||
|
*/
|
||||||
|
if (get_sha1_hex(buf.buf, sha1) ||
|
||||||
|
(40 <= buf.len && !isspace(buf.buf[40])) ||
|
||||||
|
(!is_prereq && buf.len <= 40)) {
|
||||||
|
if (report_path)
|
||||||
|
error("unrecognized header: %s%s (%d)",
|
||||||
|
(is_prereq ? "-" : ""), buf.buf, (int)buf.len);
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (is_prereq)
|
||||||
|
add_to_ref_list(sha1, "", &header->prerequisites);
|
||||||
|
else
|
||||||
|
add_to_ref_list(sha1, buf.buf + 41, &header->references);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if (status) {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
strbuf_release(&buf);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
int read_bundle_header(const char *path, struct bundle_header *header)
|
int read_bundle_header(const char *path, struct bundle_header *header)
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
int fd = open(path, O_RDONLY);
|
||||||
int fd;
|
|
||||||
long fpos;
|
|
||||||
FILE *ffd = fopen(path, "rb");
|
|
||||||
|
|
||||||
if (!ffd)
|
|
||||||
return error("could not open '%s'", path);
|
|
||||||
if (!fgets(buffer, sizeof(buffer), ffd) ||
|
|
||||||
strcmp(buffer, bundle_signature)) {
|
|
||||||
fclose(ffd);
|
|
||||||
return error("'%s' does not look like a v2 bundle file", path);
|
|
||||||
}
|
|
||||||
while (fgets(buffer, sizeof(buffer), ffd)
|
|
||||||
&& buffer[0] != '\n') {
|
|
||||||
int is_prereq = buffer[0] == '-';
|
|
||||||
int offset = is_prereq ? 1 : 0;
|
|
||||||
int len = strlen(buffer);
|
|
||||||
unsigned char sha1[20];
|
|
||||||
struct ref_list *list = is_prereq ? &header->prerequisites
|
|
||||||
: &header->references;
|
|
||||||
char delim;
|
|
||||||
|
|
||||||
if (len && buffer[len - 1] == '\n')
|
|
||||||
buffer[len - 1] = '\0';
|
|
||||||
if (get_sha1_hex(buffer + offset, sha1)) {
|
|
||||||
warning("unrecognized header: %s", buffer);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
delim = buffer[40 + offset];
|
|
||||||
if (!isspace(delim) && (delim != '\0' || !is_prereq))
|
|
||||||
die ("invalid header: %s", buffer);
|
|
||||||
add_to_ref_list(sha1, isspace(delim) ?
|
|
||||||
buffer + 41 + offset : "", list);
|
|
||||||
}
|
|
||||||
fpos = ftell(ffd);
|
|
||||||
fclose(ffd);
|
|
||||||
fd = open(path, O_RDONLY);
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return error("could not open '%s'", path);
|
return error("could not open '%s'", path);
|
||||||
lseek(fd, fpos, SEEK_SET);
|
return parse_bundle_header(fd, header, path);
|
||||||
return fd;
|
}
|
||||||
|
|
||||||
|
int is_bundle(const char *path, int quiet)
|
||||||
|
{
|
||||||
|
struct bundle_header header;
|
||||||
|
int fd = open(path, O_RDONLY);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
memset(&header, 0, sizeof(header));
|
||||||
|
fd = parse_bundle_header(fd, &header, quiet ? NULL : path);
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
return (fd >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int list_refs(struct ref_list *r, int argc, const char **argv)
|
static int list_refs(struct ref_list *r, int argc, const char **argv)
|
||||||
|
|
1
bundle.h
1
bundle.h
|
@ -14,6 +14,7 @@ struct bundle_header {
|
||||||
struct ref_list references;
|
struct ref_list references;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int is_bundle(const char *path, int quiet);
|
||||||
int read_bundle_header(const char *path, struct bundle_header *header);
|
int read_bundle_header(const char *path, struct bundle_header *header);
|
||||||
int create_bundle(struct bundle_header *header, const char *path,
|
int create_bundle(struct bundle_header *header, const char *path,
|
||||||
int argc, const char **argv);
|
int argc, const char **argv);
|
||||||
|
|
24
transport.c
24
transport.c
|
@ -859,28 +859,6 @@ static int is_local(const char *url)
|
||||||
has_dos_drive_prefix(url);
|
has_dos_drive_prefix(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_gitfile(const char *url)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
char buf[9];
|
|
||||||
int fd, len;
|
|
||||||
if (stat(url, &st))
|
|
||||||
return 0;
|
|
||||||
if (!S_ISREG(st.st_mode))
|
|
||||||
return 0;
|
|
||||||
if (st.st_size < 10 || st.st_size > 9 + PATH_MAX)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fd = open(url, O_RDONLY);
|
|
||||||
if (fd < 0)
|
|
||||||
die_errno("Error opening '%s'", url);
|
|
||||||
len = read_in_full(fd, buf, sizeof(buf));
|
|
||||||
close(fd);
|
|
||||||
if (len != sizeof(buf))
|
|
||||||
die("Error reading %s", url);
|
|
||||||
return !prefixcmp(buf, "gitdir: ");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int is_file(const char *url)
|
static int is_file(const char *url)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
|
@ -929,7 +907,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
||||||
ret->fetch = fetch_objs_via_rsync;
|
ret->fetch = fetch_objs_via_rsync;
|
||||||
ret->push = rsync_transport_push;
|
ret->push = rsync_transport_push;
|
||||||
ret->smart_options = NULL;
|
ret->smart_options = NULL;
|
||||||
} else if (is_local(url) && is_file(url) && !is_gitfile(url)) {
|
} else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
|
||||||
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
||||||
ret->data = data;
|
ret->data = data;
|
||||||
ret->get_refs_list = get_refs_from_bundle;
|
ret->get_refs_list = get_refs_from_bundle;
|
||||||
|
|
Loading…
Reference in New Issue