* Return a pointer to the refname within the line (null-terminated),
* or NULL if there was a problem.
*/
-static const char *parse_ref_line(char *line, unsigned char *sha1)
+static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
{
+ const char *ref;
+
/*
* 42: the answer to everything.
*
* +1 (space in between hex and name)
* +1 (newline at the end of the line)
*/
- int len = strlen(line) - 42;
-
- if (len <= 0)
+ if (line->len <= 42)
return NULL;
- if (get_sha1_hex(line, sha1) < 0)
+
+ if (get_sha1_hex(line->buf, sha1) < 0)
return NULL;
- if (!isspace(line[40]))
+ if (!isspace(line->buf[40]))
return NULL;
- line += 41;
- if (isspace(*line))
+
+ ref = line->buf + 41;
+ if (isspace(*ref))
return NULL;
- if (line[len] != '\n')
+
+ if (line->buf[line->len - 1] != '\n')
return NULL;
- line[len] = 0;
+ line->buf[--line->len] = 0;
- return line;
+ return ref;
}
/*
static void read_packed_refs(FILE *f, struct ref_dir *dir)
{
struct ref_entry *last = NULL;
- char refline[PATH_MAX];
+ struct strbuf line = STRBUF_INIT;
enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
- while (fgets(refline, sizeof(refline), f)) {
+ while (strbuf_getwholeline(&line, f, '\n') != EOF) {
unsigned char sha1[20];
const char *refname;
- static const char header[] = "# pack-refs with:";
+ const char *traits;
- if (!strncmp(refline, header, sizeof(header)-1)) {
- const char *traits = refline + sizeof(header) - 1;
+ if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
if (strstr(traits, " fully-peeled "))
peeled = PEELED_FULLY;
else if (strstr(traits, " peeled "))
continue;
}
- refname = parse_ref_line(refline, sha1);
+ refname = parse_ref_line(&line, sha1);
if (refname) {
int flag = REF_ISPACKED;
continue;
}
if (last &&
- refline[0] == '^' &&
- strlen(refline) == PEELED_LINE_LENGTH &&
- refline[PEELED_LINE_LENGTH - 1] == '\n' &&
- !get_sha1_hex(refline + 1, sha1)) {
+ line.buf[0] == '^' &&
+ line.len == PEELED_LINE_LENGTH &&
+ line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
+ !get_sha1_hex(line.buf + 1, sha1)) {
hashcpy(last->u.value.peeled, sha1);
/*
* Regardless of what the file header said,
last->flag |= REF_KNOWS_PEELED;
}
}
+
+ strbuf_release(&line);
}
/*
struct string_list_item *ref_to_delete;
int i, ret, removed = 0;
+ assert(err);
+
/* Look for a packed ref */
for (i = 0; i < n; i++)
if (get_packed_ref(refnames[i]))
return 0; /* no refname exists in packed refs */
if (lock_packed_refs(0)) {
- if (err) {
- unable_to_lock_message(git_path("packed-refs"), errno,
- err);
- return -1;
- }
- unable_to_lock_error(git_path("packed-refs"), errno);
- return error("cannot delete '%s' from packed refs", refnames[i]);
+ unable_to_lock_message(git_path("packed-refs"), errno, err);
+ return -1;
}
packed = get_packed_refs(&ref_cache);
/* Write what remains */
ret = commit_packed_refs();
- if (ret && err)
+ if (ret)
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
strerror(errno));
return ret;
static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
{
+ assert(err);
+
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
/*
* loose. The loose file name is the same as the
logfd = open(logfile, oflags, 0666);
if (logfd < 0) {
- if (!(oflags & O_CREAT) && errno == ENOENT)
+ if (!(oflags & O_CREAT) && (errno == ENOENT || errno == EISDIR))
return 0;
- if ((oflags & O_CREAT) && errno == EISDIR) {
+ if (errno == EISDIR) {
if (remove_empty_directories(logfile)) {
int save_errno = errno;
error("There are still logs under '%s'",
bp = find_beginning_of_line(buf, scanp);
- if (*bp != '\n') {
- strbuf_splice(&sb, 0, 0, buf, endp - buf);
- if (pos)
- break; /* need to fill another block */
- scanp = buf - 1; /* leave loop */
- } else {
+ if (*bp == '\n') {
/*
- * (bp + 1) thru endp is the beginning of the
- * current line we have in sb
+ * The newline is the end of the previous line,
+ * so we know we have complete line starting
+ * at (bp + 1). Prefix it onto any prior data
+ * we collected for the line and process it.
*/
strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
scanp = bp;
endp = bp + 1;
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ if (ret)
+ break;
+ } else if (!pos) {
+ /*
+ * We are at the start of the buffer, and the
+ * start of the file; there is no previous
+ * line, and we have everything for this one.
+ * Process it, and we can end the loop.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
+ ret = show_one_reflog_ent(&sb, fn, cb_data);
+ strbuf_reset(&sb);
+ break;
}
- ret = show_one_reflog_ent(&sb, fn, cb_data);
- strbuf_reset(&sb);
- if (ret)
+
+ if (bp == buf) {
+ /*
+ * We are at the start of the buffer, and there
+ * is more file to read backwards. Which means
+ * we are in the middle of a line. Note that we
+ * may get here even if *bp was a newline; that
+ * just means we are at the exact end of the
+ * previous line, rather than some spot in the
+ * middle.
+ *
+ * Save away what we have to be combined with
+ * the data from the next read.
+ */
+ strbuf_splice(&sb, 0, 0, buf, endp - buf);
break;
+ }
}
}
if (!ret && sb.len)
- ret = show_one_reflog_ent(&sb, fn, cb_data);
+ die("BUG: reverse reflog parser had leftover data");
fclose(logfp);
strbuf_release(&sb);
struct ref_transaction *ref_transaction_begin(struct strbuf *err)
{
+ assert(err);
+
return xcalloc(1, sizeof(struct ref_transaction));
}
{
struct ref_update *update;
+ assert(err);
+
if (transaction->state != REF_TRANSACTION_OPEN)
die("BUG: update called for transaction that is not open");
{
struct ref_update *update;
+ assert(err);
+
if (transaction->state != REF_TRANSACTION_OPEN)
die("BUG: create called for transaction that is not open");
{
struct ref_update *update;
+ assert(err);
+
if (transaction->state != REF_TRANSACTION_OPEN)
die("BUG: delete called for transaction that is not open");
struct strbuf *err)
{
int i;
+
+ assert(err);
+
for (i = 1; i < n; i++)
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
- const char *str =
- "Multiple updates for ref '%s' not allowed.";
- if (err)
- strbuf_addf(err, str, updates[i]->refname);
-
+ strbuf_addf(err,
+ "Multiple updates for ref '%s' not allowed.",
+ updates[i]->refname);
return 1;
}
return 0;
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
+ assert(err);
+
if (transaction->state != REF_TRANSACTION_OPEN)
die("BUG: commit called for transaction that is not open");
ret = (errno == ENOTDIR)
? TRANSACTION_NAME_CONFLICT
: TRANSACTION_GENERIC_ERROR;
- if (err)
- strbuf_addf(err, "Cannot lock the ref '%s'.",
- update->refname);
+ strbuf_addf(err, "Cannot lock the ref '%s'.",
+ update->refname);
goto cleanup;
}
}
if (write_ref_sha1(update->lock, update->new_sha1,
update->msg)) {
update->lock = NULL; /* freed by write_ref_sha1 */
- if (err)
- strbuf_addf(err, "Cannot update the ref '%s'.",
- update->refname);
+ strbuf_addf(err, "Cannot update the ref '%s'.",
+ update->refname);
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
struct ref_update *update = updates[i];
if (update->lock) {
- if (delete_ref_loose(update->lock, update->type, err))
+ if (delete_ref_loose(update->lock, update->type, err)) {
ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
if (!(update->flags & REF_ISPRUNING))
delnames[delnum++] = update->lock->ref_name;
}
}
- if (repack_without_refs(delnames, delnum, err))
+ if (repack_without_refs(delnames, delnum, err)) {
ret = TRANSACTION_GENERIC_ERROR;
+ goto cleanup;
+ }
for (i = 0; i < delnum; i++)
unlink_or_warn(git_path("logs/%s", delnames[i]));
clear_loose_ref_cache(&ref_cache);