Beispiel #1
0
static int entry_path_alloc(
	char **out,
	const char *path,
	size_t path_len,
	const char *de_path,
	size_t de_len,
	size_t alloc_extra)
{
	int need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
	size_t alloc_size;
	char *entry_path;

	GITERR_CHECK_ALLOC_ADD(&alloc_size, path_len, de_len);
	GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, need_slash);
	GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, 1);
	GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, alloc_extra);
	entry_path = git__calloc(1, alloc_size);
	GITERR_CHECK_ALLOC(entry_path);

	if (path_len)
		memcpy(entry_path, path, path_len);

	if (need_slash)
		entry_path[path_len] = '/';

	memcpy(&entry_path[path_len + need_slash], de_path, de_len);

	*out = entry_path;
	return 0;
}
Beispiel #2
0
static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
{
	xrecord_t **recs;
	size_t size = 0;

	*out = 0;

	recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;

	if (count < 1)
		return 0;

	for (i = 0; i < count; ) {
		if (dest)
			memcpy(dest + size, recs[i]->ptr, recs[i]->size);

		GITERR_CHECK_ALLOC_ADD(&size, size, recs[i++]->size);
	}

	if (add_nl) {
		i = recs[count - 1]->size;
		if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
			if (dest)
				dest[size] = '\n';

			GITERR_CHECK_ALLOC_ADD(&size, size, 1);
		}
	}

	*out = size;
	return 0;
}
Beispiel #3
0
int git_path_make_relative(git_buf *path, const char *parent)
{
	const char *p, *q, *p_dirsep, *q_dirsep;
	size_t plen = path->size, newlen, alloclen, depth = 1, i, offset;

	for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) {
		if (*p == '/' && *q == '/') {
			p_dirsep = p;
			q_dirsep = q;
		}
		else if (*p != *q)
			break;
	}

	/* need at least 1 common path segment */
	if ((p_dirsep == path->ptr || q_dirsep == parent) &&
		(*p_dirsep != '/' || *q_dirsep != '/')) {
		giterr_set(GITERR_INVALID,
			"%s is not a parent of %s", parent, path->ptr);
		return GIT_ENOTFOUND;
	}

	if (*p == '/' && !*q)
		p++;
	else if (!*p && *q == '/')
		q++;
	else if (!*p && !*q)
		return git_buf_clear(path), 0;
	else {
		p = p_dirsep + 1;
		q = q_dirsep + 1;
	}

	plen -= (p - path->ptr);

	if (!*q)
		return git_buf_set(path, p, plen);

	for (; (q = strchr(q, '/')) && *(q + 1); q++)
		depth++;

	GITERR_CHECK_ALLOC_MULTIPLY(&newlen, depth, 3);
	GITERR_CHECK_ALLOC_ADD(&newlen, newlen, plen);

	GITERR_CHECK_ALLOC_ADD(&alloclen, newlen, 1);

	/* save the offset as we might realllocate the pointer */
	offset = p - path->ptr;
	if (git_buf_try_grow(path, alloclen, 1, 0) < 0)
		return -1;
	p = path->ptr + offset;

	memmove(path->ptr + (depth * 3), p, plen + 1);

	for (i = 0; i < depth; i++)
		memcpy(path->ptr + (i * 3), "../", 3);

	path->size = newlen;
	return 0;
}
Beispiel #4
0
int git_buf_put_w(git_buf *buf, const wchar_t *string_w, size_t len_w)
{
	int utf8_len, utf8_write_len;
	size_t new_size;

	if (!len_w)
		return 0;

	assert(string_w);

	/* Measure the string necessary for conversion */
	if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string_w, len_w, NULL, 0, NULL, NULL)) == 0)
		return 0;

	assert(utf8_len > 0);

	GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, (size_t)utf8_len);
	GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);

	if (git_buf_grow(buf, new_size) < 0)
		return -1;

	if ((utf8_write_len = WideCharToMultiByte(
			CP_UTF8, WC_ERR_INVALID_CHARS, string_w, len_w, &buf->ptr[buf->size], utf8_len, NULL, NULL)) == 0)
		return handle_wc_error();

	assert(utf8_write_len == utf8_len);

	buf->size += utf8_write_len;
	buf->ptr[buf->size] = '\0';
	return 0;
}
Beispiel #5
0
static int xdl_fill_merge_buffer(size_t *out,
				 xdfenv_t *xe1, const char *name1,
				 xdfenv_t *xe2, const char *name2,
				 const char *ancestor_name,
				 int favor,
				 xdmerge_t *m, char *dest, int style,
				 int marker_size)
{
	size_t size, copied;
	int i;

	*out = 0;

	for (size = i = 0; m; m = m->next) {
		if (favor && !m->mode)
			m->mode = favor;

		if (m->mode == 0) {
			if (fill_conflict_hunk(&size, xe1, name1, xe2, name2,
						  ancestor_name,
						  size, i, style, m, dest,
						  marker_size) < 0)
				return -1;
		}
		else if (m->mode & 3) {
			/* Before conflicting part */
			if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0,
					      dest ? dest + size : NULL) < 0)
				return -1;
			GITERR_CHECK_ALLOC_ADD(&size, size, copied);

			/* Postimage from side #1 */
			if (m->mode & 1) {
				if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, (m->mode & 2),
						      dest ? dest + size : NULL) < 0)
					return -1;
				GITERR_CHECK_ALLOC_ADD(&size, size, copied);
			}

			/* Postimage from side #2 */
			if (m->mode & 2) {
				if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 0,
						      dest ? dest + size : NULL) < 0)
					return -1;
				GITERR_CHECK_ALLOC_ADD(&size, size, copied);
			}
		} else
			continue;
		i = m->i1 + m->chg1;
	}

	if (xdl_recs_copy(&copied, xe1, i, xe1->xdf2.nrec - i, 0,
			      dest ? dest + size : NULL) < 0)
		return -1;
	GITERR_CHECK_ALLOC_ADD(&size, size, copied);

	*out = size;
	return 0;
}
Beispiel #6
0
int git_odb_backend_loose(
	git_odb_backend **backend_out,
	const char *objects_dir,
	int compression_level,
	int do_fsync,
	unsigned int dir_mode,
	unsigned int file_mode)
{
	loose_backend *backend;
	size_t objects_dirlen, alloclen;

	assert(backend_out && objects_dir);

	objects_dirlen = strlen(objects_dir);

	GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(loose_backend), objects_dirlen);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 2);
	backend = git__calloc(1, alloclen);
	GITERR_CHECK_ALLOC(backend);

	backend->parent.version = GIT_ODB_BACKEND_VERSION;
	backend->objects_dirlen = objects_dirlen;
	memcpy(backend->objects_dir, objects_dir, objects_dirlen);
	if (backend->objects_dir[backend->objects_dirlen - 1] != '/')
		backend->objects_dir[backend->objects_dirlen++] = '/';

	if (compression_level < 0)
		compression_level = Z_BEST_SPEED;

	if (dir_mode == 0)
		dir_mode = GIT_OBJECT_DIR_MODE;

	if (file_mode == 0)
		file_mode = GIT_OBJECT_FILE_MODE;

	backend->object_zlib_level = compression_level;
	backend->fsync_object_files = do_fsync;
	backend->object_dir_mode = dir_mode;
	backend->object_file_mode = file_mode;

	backend->parent.read = &loose_backend__read;
	backend->parent.write = &loose_backend__write;
	backend->parent.read_prefix = &loose_backend__read_prefix;
	backend->parent.read_header = &loose_backend__read_header;
	backend->parent.writestream = &loose_backend__writestream;
	backend->parent.readstream = &loose_backend__readstream;
	backend->parent.exists = &loose_backend__exists;
	backend->parent.exists_prefix = &loose_backend__exists_prefix;
	backend->parent.foreach = &loose_backend__foreach;
	backend->parent.freshen = &loose_backend__freshen;
	backend->parent.free = &loose_backend__free;

	*backend_out = (git_odb_backend *)backend;
	return 0;
}
Beispiel #7
0
static int ok_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_ok *pkt;
	const char *ptr;
	size_t alloc_len;

	pkt = git__malloc(sizeof(*pkt));
	GITERR_CHECK_ALLOC(pkt);

	pkt->type = GIT_PKT_OK;

	line += 3; /* skip "ok " */
	if (!(ptr = strchr(line, '\n'))) {
		giterr_set(GITERR_NET, "invalid packet line");
		git__free(pkt);
		return -1;
	}
	len = ptr - line;

	GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
	pkt->ref = git__malloc(alloc_len);
	GITERR_CHECK_ALLOC(pkt->ref);

	memcpy(pkt->ref, line, len);
	pkt->ref[len] = '\0';

	*out = (git_pkt *)pkt;
	return 0;
}
Beispiel #8
0
int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
{
	ssize_t read_size = 0;
	size_t alloc_len;

	git_buf_clear(buf);

	if (!git__is_ssizet(len)) {
		giterr_set(GITERR_INVALID, "read too large");
		return -1;
	}

	GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
	if (git_buf_grow(buf, alloc_len) < 0)
		return -1;

	/* p_read loops internally to read len bytes */
	read_size = p_read(fd, buf->ptr, len);

	if (read_size != (ssize_t)len) {
		giterr_set(GITERR_OS, "failed to read descriptor");
		git_buf_free(buf);
		return -1;
	}

	buf->ptr[read_size] = '\0';
	buf->size = read_size;

	return 0;
}
Beispiel #9
0
static int ng_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_ng *pkt;
	const char *ptr;
	size_t alloclen;

	pkt = git__malloc(sizeof(*pkt));
	GITERR_CHECK_ALLOC(pkt);

	pkt->ref = NULL;
	pkt->type = GIT_PKT_NG;

	line += 3; /* skip "ng " */
	if (!(ptr = strchr(line, ' ')))
		goto out_err;
	len = ptr - line;

	GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
	pkt->ref = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt->ref);

	memcpy(pkt->ref, line, len);
	pkt->ref[len] = '\0';

	line = ptr + 1;
	if (!(ptr = strchr(line, '\n')))
		goto out_err;
	len = ptr - line;

	GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
	pkt->msg = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt->msg);

	memcpy(pkt->msg, line, len);
	pkt->msg[len] = '\0';

	*out = (git_pkt *)pkt;
	return 0;

out_err:
	giterr_set(GITERR_NET, "invalid packet line");
	git__free(pkt->ref);
	git__free(pkt);
	return -1;
}
Beispiel #10
0
int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
{
    const char *start = src->ptr;
    const char *end = start + src->size;
    const char *scan = start;
    const char *next = memchr(scan, '\n', src->size);
    size_t alloclen;

    assert(tgt != src);

    if (!next)
        return git_buf_set(tgt, src->ptr, src->size);

    /* attempt to reduce reallocs while in the loop */
    GITERR_CHECK_ALLOC_ADD(&alloclen, src->size, src->size >> 4);
    GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
    if (git_buf_grow(tgt, alloclen) < 0)
        return -1;
    tgt->size = 0;

    for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
        size_t copylen = next - scan;

        /* if we find mixed line endings, bail */
        if (next > start && next[-1] == '\r') {
            git_buf_free(tgt);
            return GIT_PASSTHROUGH;
        }

        GITERR_CHECK_ALLOC_ADD(&alloclen, copylen, 3);
        if (git_buf_grow_by(tgt, alloclen) < 0)
            return -1;

        if (next > scan) {
            memcpy(tgt->ptr + tgt->size, scan, copylen);
            tgt->size += copylen;
        }

        tgt->ptr[tgt->size++] = '\r';
        tgt->ptr[tgt->size++] = '\n';
    }

    tgt->ptr[tgt->size] = '\0';
    return git_buf_put(tgt, scan, end - scan);
}
Beispiel #11
0
static int comment_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_comment *pkt;
	size_t alloclen;

	GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_comment), len);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
	pkt = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt);

	pkt->type = GIT_PKT_COMMENT;
	memcpy(pkt->comment, line, len);
	pkt->comment[len] = '\0';

	*out = (git_pkt *) pkt;

	return 0;
}
Beispiel #12
0
int git_path_iconv(git_path_iconv_t *ic, const char **in, size_t *inlen)
{
	char *nfd = *in, *nfc;
	size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, alloclen, rv;
	int retry = 1;

	if (!ic || ic->map == (iconv_t)-1 ||
		!git_path_has_non_ascii(*in, *inlen))
		return 0;

	git_buf_clear(&ic->buf);

	while (1) {
		GITERR_CHECK_ALLOC_ADD(&alloclen, wantlen, 1);
		if (git_buf_grow(&ic->buf, alloclen) < 0)
			return -1;

		nfc    = ic->buf.ptr   + ic->buf.size;
		nfclen = ic->buf.asize - ic->buf.size;

		rv = iconv(ic->map, &nfd, &nfdlen, &nfc, &nfclen);

		ic->buf.size = (nfc - ic->buf.ptr);

		if (rv != (size_t)-1)
			break;

		/* if we cannot convert the data (probably because iconv thinks
		 * it is not valid UTF-8 source data), then use original data
		 */
		if (errno != E2BIG)
			return 0;

		/* make space for 2x the remaining data to be converted
		 * (with per retry overhead to avoid infinite loops)
		 */
		wantlen = ic->buf.size + max(nfclen, nfdlen) * 2 + (size_t)(retry * 4);

		if (retry++ > 4)
			goto fail;
	}

	ic->buf.ptr[ic->buf.size] = '\0';

	*in    = ic->buf.ptr;
	*inlen = ic->buf.size;

	return 0;

fail:
	giterr_set(GITERR_OS, "Unable to convert unicode path data");
	return -1;
}
Beispiel #13
0
static int object_file_name(
	git_buf *name, const loose_backend *be, const git_oid *id)
{
	size_t alloclen;

	/* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */
	GITERR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3);
	if (git_buf_grow(name, alloclen) < 0)
		return -1;

	git_buf_set(name, be->objects_dir, be->objects_dirlen);
	git_path_to_dir(name);

	/* loose object filename: aa/aaa... (41 bytes) */
	git_oid_pathfmt(name->ptr + name->size, id);
	name->size += GIT_OID_HEXSZ + 1;
	name->ptr[name->size] = '\0';

	return 0;
}
Beispiel #14
0
static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_err *pkt;
	size_t alloc_len;

	line++;
	len--;

	GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len);
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
	pkt = git__malloc(alloc_len);
	GITERR_CHECK_ALLOC(pkt);

	pkt->type = GIT_PKT_ERR;
	pkt->len = (int)len;
	memcpy(pkt->error, line, len);
	pkt->error[len] = '\0';

	*out = (git_pkt *)pkt;

	return 0;
}
Beispiel #15
0
static int diff_driver_alloc(
	git_diff_driver **out, size_t *namelen_out, const char *name)
{
	git_diff_driver *driver;
	size_t driverlen = sizeof(git_diff_driver),
		namelen = strlen(name),
		alloclen;

	GITERR_CHECK_ALLOC_ADD(&alloclen, driverlen, namelen);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);

	driver = git__calloc(1, alloclen);
	GITERR_CHECK_ALLOC(driver);

	memcpy(driver->name, name, namelen);

	*out = driver;

	if (namelen_out)
		*namelen_out = namelen;

	return 0;
}
Beispiel #16
0
/* Given a commit and a path in it, create a new origin structure. */
static int make_origin(git_blame__origin **out, git_commit *commit, const char *path)
{
	git_blame__origin *o;
	size_t path_len = strlen(path), alloc_len;
	int error = 0;

	GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*o), path_len);
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
	o = git__calloc(1, alloc_len);
	GITERR_CHECK_ALLOC(o);

	o->commit = commit;
	o->refcnt = 1;
	strcpy(o->path, path);

	if (!(error = git_object_lookup_bypath((git_object**)&o->blob, (git_object*)commit,
			path, GIT_OBJ_BLOB))) {
		*out = o;
	} else {
		origin_decref(o);
	}
	return error;
}
Beispiel #17
0
static int err_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_err *pkt;
	size_t alloclen;

	/* Remove "ERR " from the line */
	line += 4;
	len -= 4;

	GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
	pkt = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt);

	pkt->type = GIT_PKT_ERR;
	pkt->len = (int)len;
	memcpy(pkt->error, line, len);
	pkt->error[len] = '\0';

	*out = (git_pkt *) pkt;

	return 0;
}
Beispiel #18
0
int git_buf_text_puts_escaped(
    git_buf *buf,
    const char *string,
    const char *esc_chars,
    const char *esc_with)
{
    const char *scan;
    size_t total = 0, esc_len = strlen(esc_with), count, alloclen;

    if (!string)
        return 0;

    for (scan = string; *scan; ) {
        /* count run of non-escaped characters */
        count = strcspn(scan, esc_chars);
        total += count;
        scan += count;
        /* count run of escaped characters */
        count = strspn(scan, esc_chars);
        total += count * (esc_len + 1);
        scan += count;
    }

    GITERR_CHECK_ALLOC_ADD(&alloclen, total, 1);
    if (git_buf_grow_by(buf, alloclen) < 0)
        return -1;

    for (scan = string; *scan; ) {
        count = strcspn(scan, esc_chars);

        memmove(buf->ptr + buf->size, scan, count);
        scan += count;
        buf->size += count;

        for (count = strspn(scan, esc_chars); count > 0; --count) {
            /* copy escape sequence */
            memmove(buf->ptr + buf->size, esc_with, esc_len);
            buf->size += esc_len;
            /* copy character to be escaped */
            buf->ptr[buf->size] = *scan;
            buf->size++;
            scan++;
        }
    }

    buf->ptr[buf->size] = '\0';

    return 0;
}
Beispiel #19
0
int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
{
    const char *scan = src->ptr;
    const char *scan_end = src->ptr + src->size;
    const char *next = memchr(scan, '\r', src->size);
    size_t new_size;
    char *out;

    assert(tgt != src);

    if (!next)
        return git_buf_set(tgt, src->ptr, src->size);

    /* reduce reallocs while in the loop */
    GITERR_CHECK_ALLOC_ADD(&new_size, src->size, 1);
    if (git_buf_grow(tgt, new_size) < 0)
        return -1;

    out = tgt->ptr;
    tgt->size = 0;

    /* Find the next \r and copy whole chunk up to there to tgt */
    for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) {
        if (next > scan) {
            size_t copylen = (size_t)(next - scan);
            memcpy(out, scan, copylen);
            out += copylen;
        }

        /* Do not drop \r unless it is followed by \n */
        if (next + 1 == scan_end || next[1] != '\n')
            *out++ = '\r';
    }

    /* Copy remaining input into dest */
    if (scan < scan_end) {
        size_t remaining = (size_t)(scan_end - scan);
        memcpy(out, scan, remaining);
        out += remaining;
    }

    tgt->size = (size_t)(out - tgt->ptr);
    tgt->ptr[tgt->size] = '\0';

    return 0;
}
Beispiel #20
0
/*
 * Parse an other-ref line.
 */
static int ref_pkt(git_pkt **out, const char *line, size_t len)
{
	int error;
	git_pkt_ref *pkt;
	size_t alloclen;

	pkt = git__malloc(sizeof(git_pkt_ref));
	GITERR_CHECK_ALLOC(pkt);

	memset(pkt, 0x0, sizeof(git_pkt_ref));
	pkt->type = GIT_PKT_REF;
	if ((error = git_oid_fromstr(&pkt->head.oid, line)) < 0)
		goto error_out;

	/* Check for a bit of consistency */
	if (line[GIT_OID_HEXSZ] != ' ') {
		giterr_set(GITERR_NET, "error parsing pkt-line");
		error = -1;
		goto error_out;
	}

	/* Jump from the name */
	line += GIT_OID_HEXSZ + 1;
	len -= (GIT_OID_HEXSZ + 1);

	if (line[len - 1] == '\n')
		--len;

	GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
	pkt->head.name = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt->head.name);

	memcpy(pkt->head.name, line, len);
	pkt->head.name[len] = '\0';

	if (strlen(pkt->head.name) < len) {
		pkt->capabilities = strchr(pkt->head.name, '\0') + 1;
	}

	*out = (git_pkt *)pkt;
	return 0;

error_out:
	git__free(pkt);
	return error;
}
Beispiel #21
0
static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len)
{
	git_pkt_progress *pkt;
	size_t alloclen;

	line++;
	len--;

	GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len);
	pkt = git__malloc(alloclen);
	GITERR_CHECK_ALLOC(pkt);

	pkt->type = GIT_PKT_PROGRESS;
	pkt->len = (int) len;
	memcpy(pkt->data, line, len);

	*out = (git_pkt *) pkt;

	return 0;
}
Beispiel #22
0
static int tree_iterator__push_frame(tree_iterator *ti)
{
	int error = 0;
	tree_iterator_frame *head = ti->head, *tf = NULL;
	size_t i, n_entries = 0, alloclen;

	if (head->current >= head->n_entries || !head->entries[head->current]->tree)
		return GIT_ITEROVER;

	for (i = head->current; i < head->next; ++i)
		n_entries += git_tree_entrycount(head->entries[i]->tree);

	GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, sizeof(tree_iterator_entry *), n_entries);
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, sizeof(tree_iterator_frame));

	tf = git__calloc(1, alloclen);
	GITERR_CHECK_ALLOC(tf);

	tf->n_entries = n_entries;

	tf->up     = head;
	head->down = tf;
	ti->head   = tf;

	for (i = head->current, n_entries = 0; i < head->next; ++i) {
		git_tree *tree = head->entries[i]->tree;
		size_t j, max_j = git_tree_entrycount(tree);

		for (j = 0; j < max_j; ++j) {
			tree_iterator_entry *entry = git_pool_malloc(&ti->pool, 1);
			GITERR_CHECK_ALLOC(entry);

			entry->parent = head->entries[i];
			entry->te     = git_tree_entry_byindex(tree, j);
			entry->tree   = NULL;

			tf->entries[n_entries++] = entry;
		}
	}

	/* if ignore_case, sort entries case insensitively */
	if (iterator__ignore_case(ti))
		git__tsort_r(
			(void **)tf->entries, tf->n_entries, tree_iterator__ci_cmp, tf);

	/* pick tf->current based on "start" (or start at zero) */
	if (head->startlen > 0) {
		git__bsearch_r((void **)tf->entries, tf->n_entries, head,
			tree_iterator__search_cmp, ti, &tf->current);

		while (tf->current &&
			   !tree_iterator__search_cmp(head, tf->entries[tf->current-1], ti))
			tf->current--;

		if ((tf->start = strchr(head->start, '/')) != NULL) {
			tf->start++;
			tf->startlen = strlen(tf->start);
		}
	}

	ti->path_has_filename = ti->entry_is_current = false;

	if ((error = tree_iterator__set_next(ti, tf)) < 0)
		return error;

	/* autoexpand as needed */
	if (!iterator__include_trees(ti) && tree_iterator__at_tree(ti))
		return tree_iterator__push_frame(ti);

	return 0;
}
Beispiel #23
0
/* Locate an object matching a given short oid */
static int locate_object_short_oid(
	git_buf *object_location,
	git_oid *res_oid,
	loose_backend *backend,
	const git_oid *short_oid,
	size_t len)
{
	char *objects_dir = backend->objects_dir;
	size_t dir_len = strlen(objects_dir), alloc_len;
	loose_locate_object_state state;
	int error;

	/* prealloc memory for OBJ_DIR/xx/xx..38x..xx */
	GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3);
	if (git_buf_grow(object_location, alloc_len) < 0)
		return -1;

	git_buf_set(object_location, objects_dir, dir_len);
	git_path_to_dir(object_location);

	/* save adjusted position at end of dir so it can be restored later */
	dir_len = git_buf_len(object_location);

	/* Convert raw oid to hex formatted oid */
	git_oid_fmt((char *)state.short_oid, short_oid);

	/* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
	if (git_buf_put(object_location, (char *)state.short_oid, 3) < 0)
		return -1;
	object_location->ptr[object_location->size - 1] = '/';

	/* Check that directory exists */
	if (git_path_isdir(object_location->ptr) == false)
		return git_odb__error_notfound("no matching loose object for prefix",
			short_oid, len);

	state.dir_len = git_buf_len(object_location);
	state.short_oid_len = len;
	state.found = 0;

	/* Explore directory to find a unique object matching short_oid */
	error = git_path_direach(
		object_location, 0, fn_locate_object_short_oid, &state);
	if (error < 0 && error != GIT_EAMBIGUOUS)
		return error;

	if (!state.found)
		return git_odb__error_notfound("no matching loose object for prefix",
			short_oid, len);

	if (state.found > 1)
		return git_odb__error_ambiguous("multiple matches in loose objects");

	/* Convert obtained hex formatted oid to raw */
	error = git_oid_fromstr(res_oid, (char *)state.res_oid);
	if (error)
		return error;

	/* Update the location according to the oid obtained */
	GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);

	git_buf_truncate(object_location, dir_len);
	if (git_buf_grow(object_location, alloc_len) < 0)
		return -1;

	git_oid_pathfmt(object_location->ptr + dir_len, res_oid);

	object_location->size += GIT_OID_HEXSZ + 1;
	object_location->ptr[object_location->size] = '\0';

	return 0;
}
Beispiel #24
0
static int parse_section_header_ext(git_config_parser *reader, const char *line, const char *base_name, char **section_name)
{
	int c, rpos;
	char *first_quote, *last_quote;
	git_buf buf = GIT_BUF_INIT;
	size_t quoted_len, alloc_len, base_name_len = strlen(base_name);

	/*
	 * base_name is what came before the space. We should be at the
	 * first quotation mark, except for now, line isn't being kept in
	 * sync so we only really use it to calculate the length.
	 */

	first_quote = strchr(line, '"');
	if (first_quote == NULL) {
		set_parse_error(reader, 0, "Missing quotation marks in section header");
		goto end_error;
	}

	last_quote = strrchr(line, '"');
	quoted_len = last_quote - first_quote;

	if (quoted_len == 0) {
		set_parse_error(reader, 0, "Missing closing quotation mark in section header");
		goto end_error;
	}

	GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len);
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);

	if (git_buf_grow(&buf, alloc_len) < 0 ||
	    git_buf_printf(&buf, "%s.", base_name) < 0)
		goto end_error;

	rpos = 0;

	line = first_quote;
	c = line[++rpos];

	/*
	 * At the end of each iteration, whatever is stored in c will be
	 * added to the string. In case of error, jump to out
	 */
	do {

		switch (c) {
		case 0:
			set_parse_error(reader, 0, "Unexpected end-of-line in section header");
			goto end_error;

		case '"':
			goto end_parse;

		case '\\':
			c = line[++rpos];

			if (c == 0) {
				set_parse_error(reader, rpos, "Unexpected end-of-line in section header");
				goto end_error;
			}

		default:
			break;
		}

		git_buf_putc(&buf, (char)c);
		c = line[++rpos];
	} while (line + rpos < last_quote);

end_parse:
	if (git_buf_oom(&buf))
		goto end_error;

	if (line[rpos] != '"' || line[rpos + 1] != ']') {
		set_parse_error(reader, rpos, "Unexpected text after closing quotes");
		git_buf_free(&buf);
		return -1;
	}

	*section_name = git_buf_detach(&buf);
	return 0;

end_error:
	git_buf_free(&buf);

	return -1;
}
Beispiel #25
0
int git_futils_mkdir_ext(
	const char *path,
	const char *base,
	mode_t mode,
	uint32_t flags,
	struct git_futils_mkdir_options *opts)
{
	int error = -1;
	git_buf make_path = GIT_BUF_INIT;
	ssize_t root = 0, min_root_len, root_len;
	char lastch = '/', *tail;
	struct stat st;

	/* build path and find "root" where we should start calling mkdir */
	if (git_path_join_unrooted(&make_path, path, base, &root) < 0)
		return -1;

	if (make_path.size == 0) {
		giterr_set(GITERR_OS, "Attempt to create empty path");
		goto done;
	}

	/* Trim trailing slashes (except the root) */
	if ((root_len = git_path_root(make_path.ptr)) < 0)
		root_len = 0;
	else
		root_len++;

	while (make_path.size > (size_t)root_len &&
		make_path.ptr[make_path.size - 1] == '/')
		make_path.ptr[--make_path.size] = '\0';

	/* if we are not supposed to made the last element, truncate it */
	if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
		git_path_dirname_r(&make_path, make_path.ptr);
		flags |= GIT_MKDIR_SKIP_LAST;
	}
	if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
		git_path_dirname_r(&make_path, make_path.ptr);
	}

	/* We were either given the root path (or trimmed it to
	 * the root), we don't have anything to do.
	 */
	if (make_path.size <= (size_t)root_len) {
		error = 0;
		goto done;
	}

	/* if we are not supposed to make the whole path, reset root */
	if ((flags & GIT_MKDIR_PATH) == 0)
		root = git_buf_rfind(&make_path, '/');

	/* advance root past drive name or network mount prefix */
	min_root_len = git_path_root(make_path.ptr);
	if (root < min_root_len)
		root = min_root_len;
	while (root >= 0 && make_path.ptr[root] == '/')
		++root;

	/* clip root to make_path length */
	if (root > (ssize_t)make_path.size)
		root = (ssize_t)make_path.size; /* i.e. NUL byte of string */
	if (root < 0)
		root = 0;

	/* walk down tail of path making each directory */
	for (tail = &make_path.ptr[root]; *tail; *tail = lastch) {

		/* advance tail to include next path component */
		while (*tail == '/')
			tail++;
		while (*tail && *tail != '/')
			tail++;

		/* truncate path at next component */
		lastch = *tail;
		*tail = '\0';
		st.st_mode = 0;

		if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
			continue;

		/* See what's going on with this path component */
		opts->perfdata.stat_calls++;

		if (p_lstat(make_path.ptr, &st) < 0) {
			opts->perfdata.mkdir_calls++;

			if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) {
				giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
				error = GIT_EEXISTS;
				goto done;
			}

			giterr_clear();
		} else {
			/* with exclusive create, existing dir is an error */
			if ((flags & GIT_MKDIR_EXCL) != 0) {
				giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr);
				error = GIT_EEXISTS;
				goto done;
			}

			if ((error = validate_existing(
				make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
					goto done;
		}

		/* chmod if requested and necessary */
		if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 ||
			 (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
			st.st_mode != mode) {

			opts->perfdata.chmod_calls++;

			if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
				lastch == '\0') {
				giterr_set(GITERR_OS, "Failed to set permissions on '%s'",
					make_path.ptr);
				goto done;
			}
		}

		if (opts->dir_map && opts->pool) {
			char *cache_path;
			size_t alloc_size;

			GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
			if (!git__is_uint32(alloc_size))
				return -1;
			cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size);
			GITERR_CHECK_ALLOC(cache_path);

			memcpy(cache_path, make_path.ptr, make_path.size + 1);

			git_strmap_insert(opts->dir_map, cache_path, cache_path, error);
			if (error < 0)
				goto done;
		}
	}

	error = 0;

	/* check that full path really is a directory if requested & needed */
	if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
		lastch != '\0') {
		opts->perfdata.stat_calls++;

		if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
			giterr_set(GITERR_OS, "Path is not a directory '%s'",
				make_path.ptr);
			error = GIT_ENOTFOUND;
		}
	}

done:
	git_buf_free(&make_path);
	return error;
}
Beispiel #26
0
static int parse_section_header(git_config_parser *reader, char **section_out)
{
	char *name, *name_end;
	int name_length, c, pos;
	int result;
	char *line;
	size_t line_len;

	git_parse_advance_ws(&reader->ctx);
	line = git__strndup(reader->ctx.line, reader->ctx.line_len);
	if (line == NULL)
		return -1;

	/* find the end of the variable's name */
	name_end = strrchr(line, ']');
	if (name_end == NULL) {
		git__free(line);
		set_parse_error(reader, 0, "Missing ']' in section header");
		return -1;
	}

	GITERR_CHECK_ALLOC_ADD(&line_len, (size_t)(name_end - line), 1);
	name = git__malloc(line_len);
	GITERR_CHECK_ALLOC(name);

	name_length = 0;
	pos = 0;

	/* Make sure we were given a section header */
	c = line[pos++];
	assert(c == '[');

	c = line[pos++];

	do {
		if (git__isspace(c)){
			name[name_length] = '\0';
			result = parse_section_header_ext(reader, line, name, section_out);
			git__free(line);
			git__free(name);
			return result;
		}

		if (!config_keychar(c) && c != '.') {
			set_parse_error(reader, pos, "Unexpected character in header");
			goto fail_parse;
		}

		name[name_length++] = (char)git__tolower(c);

	} while ((c = line[pos++]) != ']');

	if (line[pos - 1] != ']') {
		set_parse_error(reader, pos, "Unexpected end of file");
		goto fail_parse;
	}

	git__free(line);

	name[name_length] = 0;
	*section_out = name;

	return 0;

fail_parse:
	git__free(line);
	git__free(name);
	return -1;
}
Beispiel #27
0
int git_futils_mkdir_relative(
	const char *relative_path,
	const char *base,
	mode_t mode,
	uint32_t flags,
	struct git_futils_mkdir_options *opts)
{
	git_buf make_path = GIT_BUF_INIT;
	ssize_t root = 0, min_root_len;
	char lastch = '/', *tail;
	struct stat st;
	struct git_futils_mkdir_options empty_opts = {0};
	int error;

	if (!opts)
		opts = &empty_opts;

	/* build path and find "root" where we should start calling mkdir */
	if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0)
		return -1;

	if ((error = mkdir_canonicalize(&make_path, flags)) < 0 ||
		make_path.size == 0)
		goto done;

	/* if we are not supposed to make the whole path, reset root */
	if ((flags & GIT_MKDIR_PATH) == 0)
		root = git_buf_rfind(&make_path, '/');

	/* advance root past drive name or network mount prefix */
	min_root_len = git_path_root(make_path.ptr);
	if (root < min_root_len)
		root = min_root_len;
	while (root >= 0 && make_path.ptr[root] == '/')
		++root;

	/* clip root to make_path length */
	if (root > (ssize_t)make_path.size)
		root = (ssize_t)make_path.size; /* i.e. NUL byte of string */
	if (root < 0)
		root = 0;

	/* walk down tail of path making each directory */
	for (tail = &make_path.ptr[root]; *tail; *tail = lastch) {
		bool mkdir_attempted = false;

		/* advance tail to include next path component */
		while (*tail == '/')
			tail++;
		while (*tail && *tail != '/')
			tail++;

		/* truncate path at next component */
		lastch = *tail;
		*tail = '\0';
		st.st_mode = 0;

		if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
			continue;

		/* See what's going on with this path component */
		opts->perfdata.stat_calls++;

retry_lstat:
		if (p_lstat(make_path.ptr, &st) < 0) {
			if (mkdir_attempted || errno != ENOENT) {
				giterr_set(GITERR_OS, "cannot access component in path '%s'", make_path.ptr);
				error = -1;
				goto done;
			}

			giterr_clear();
			opts->perfdata.mkdir_calls++;
			mkdir_attempted = true;
			if (p_mkdir(make_path.ptr, mode) < 0) {
				if (errno == EEXIST)
					goto retry_lstat;
				giterr_set(GITERR_OS, "failed to make directory '%s'", make_path.ptr);
				error = -1;
				goto done;
			}
		} else {
			if ((error = mkdir_validate_dir(
				make_path.ptr, &st, mode, flags, opts)) < 0)
				goto done;
		}

		/* chmod if requested and necessary */
		if ((error = mkdir_validate_mode(
			make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
			goto done;

		if (opts->dir_map && opts->pool) {
			char *cache_path;
			size_t alloc_size;

			GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
			if (!git__is_uint32(alloc_size))
				return -1;
			cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size);
			GITERR_CHECK_ALLOC(cache_path);

			memcpy(cache_path, make_path.ptr, make_path.size + 1);

			git_strmap_insert(opts->dir_map, cache_path, cache_path, &error);
			if (error < 0)
				goto done;
		}
	}

	error = 0;

	/* check that full path really is a directory if requested & needed */
	if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
		lastch != '\0') {
		opts->perfdata.stat_calls++;

		if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
			giterr_set(GITERR_OS, "path is not a directory '%s'",
				make_path.ptr);
			error = GIT_ENOTFOUND;
		}
	}

done:
	git_buf_free(&make_path);
	return error;
}
Beispiel #28
0
static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
{
    static const char *tag_types[] = {
        NULL, "commit\n", "tree\n", "blob\n", "tag\n"
    };

    unsigned int i;
    size_t text_len, alloc_len;
    char *search;

    if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
        return tag_error("Object field invalid");

    if (buffer + 5 >= buffer_end)
        return tag_error("Object too short");

    if (memcmp(buffer, "type ", 5) != 0)
        return tag_error("Type field not found");
    buffer += 5;

    tag->type = GIT_OBJ_BAD;

    for (i = 1; i < ARRAY_SIZE(tag_types); ++i) {
        size_t type_length = strlen(tag_types[i]);

        if (buffer + type_length >= buffer_end)
            return tag_error("Object too short");

        if (memcmp(buffer, tag_types[i], type_length) == 0) {
            tag->type = i;
            buffer += type_length;
            break;
        }
    }

    if (tag->type == GIT_OBJ_BAD)
        return tag_error("Invalid object type");

    if (buffer + 4 >= buffer_end)
        return tag_error("Object too short");

    if (memcmp(buffer, "tag ", 4) != 0)
        return tag_error("Tag field not found");

    buffer += 4;

    search = memchr(buffer, '\n', buffer_end - buffer);
    if (search == NULL)
        return tag_error("Object too short");

    text_len = search - buffer;

    GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1);
    tag->tag_name = git__malloc(alloc_len);
    GITERR_CHECK_ALLOC(tag->tag_name);

    memcpy(tag->tag_name, buffer, text_len);
    tag->tag_name[text_len] = '\0';

    buffer = search + 1;

    tag->tagger = NULL;
    if (buffer < buffer_end && *buffer != '\n') {
        tag->tagger = git__malloc(sizeof(git_signature));
        GITERR_CHECK_ALLOC(tag->tagger);

        if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0)
            return -1;
    }

    tag->message = NULL;
    if (buffer < buffer_end) {
        if( *buffer != '\n' )
            return tag_error("No new line before message");

        text_len = buffer_end - ++buffer;

        GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1);
        tag->message = git__malloc(alloc_len);
        GITERR_CHECK_ALLOC(tag->message);

        memcpy(tag->message, buffer, text_len);
        tag->message[text_len] = '\0';
    }

    return 0;
}
Beispiel #29
0
static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
			      xdfenv_t *xe2, const char *name2,
			      const char *name3,
			      size_t size, int i, int style,
			      xdmerge_t *m, char *dest, int marker_size)
{
	int marker1_size = (name1 ? (int)strlen(name1) + 1 : 0);
	int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0);
	int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0);
	size_t copied;

	*out = 0;

	if (marker_size <= 0)
		marker_size = DEFAULT_CONFLICT_MARKER_SIZE;

	/* Before conflicting part */
	if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0,
			      dest ? dest + size : NULL) < 0)
		return -1;

	GITERR_CHECK_ALLOC_ADD(&size, size, copied);

	if (!dest) {
		GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker1_size);
	} else {
		memset(dest + size, '<', marker_size);
		size += marker_size;
		if (marker1_size) {
			dest[size] = ' ';
			memcpy(dest + size + 1, name1, marker1_size - 1);
			size += marker1_size;
		}
		dest[size++] = '\n';
	}

	/* Postimage from side #1 */
	if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, 1,
			      dest ? dest + size : NULL) < 0)
		return -1;

	GITERR_CHECK_ALLOC_ADD(&size, size, copied);

	if (style == XDL_MERGE_DIFF3) {
		/* Shared preimage */
		if (!dest) {
			GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker3_size);
		} else {
			memset(dest + size, '|', marker_size);
			size += marker_size;
			if (marker3_size) {
				dest[size] = ' ';
				memcpy(dest + size + 1, name3, marker3_size - 1);
				size += marker3_size;
			}
			dest[size++] = '\n';
		}

		if (xdl_orig_copy(&copied, xe1, m->i0, m->chg0, 1,
				      dest ? dest + size : NULL) < 0)
			return -1;
		GITERR_CHECK_ALLOC_ADD(&size, size, copied);
	}

	if (!dest) {
		GITERR_CHECK_ALLOC_ADD3(&size, size, marker_size, 1);
	} else {
		memset(dest + size, '=', marker_size);
		size += marker_size;
		dest[size++] = '\n';
	}

	/* Postimage from side #2 */

	if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 1,
			      dest ? dest + size : NULL) < 0)
		return -1;
	GITERR_CHECK_ALLOC_ADD(&size, size, copied);

	if (!dest) {
		GITERR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, marker2_size);
	} else {
		memset(dest + size, '>', marker_size);
		size += marker_size;
		if (marker2_size) {
			dest[size] = ' ';
			memcpy(dest + size + 1, name2, marker2_size - 1);
			size += marker2_size;
		}
		dest[size++] = '\n';
	}

	*out = size;
	return 0;
}