Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bundle.c99
1 files changed, 64 insertions, 35 deletions
diff --git a/bundle.c b/bundle.c
index f48fd7d4c1..3aa715c40a 100644
--- a/bundle.c
+++ b/bundle.c
@@ -23,49 +23,78 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name,
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;
+}
+
int read_bundle_header(const char *path, struct bundle_header *header)
{
- char buffer[1024];
- int fd;
- long fpos;
- FILE *ffd = fopen(path, "rb");
+ struct strbuf buf = STRBUF_INIT;
+ int fd = open(path, O_RDONLY);
+ int status = 0;
- if (!ffd)
+ if (fd < 0)
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);
+
+ /* The bundle header begins with the signature */
+ if (strbuf_readline_fd(&buf, fd) ||
+ strcmp(buf.buf, bundle_signature)) {
+ error("'%s' does not look like a v2 bundle file", path);
+ status = -1;
+ goto abort;
}
- while (fgets(buffer, sizeof(buffer), ffd)
- && buffer[0] != '\n') {
- int is_prereq = buffer[0] == '-';
- int offset = is_prereq ? 1 : 0;
- int len = strlen(buffer);
+
+ /* The bundle header ends with an empty line */
+ while (!strbuf_readline_fd(&buf, fd) &&
+ buf.len && buf.buf[0] != '\n') {
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;
+ 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)) {
+ 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);
}
- 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)
- return error("could not open '%s'", path);
- lseek(fd, fpos, SEEK_SET);
+
+ abort:
+ if (status) {
+ close(fd);
+ fd = -1;
+ }
+ strbuf_release(&buf);
return fd;
}