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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
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; }
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; }
/* * 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; }
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; }
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; }
/* 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; }
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; }
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; }
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; }
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; }
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; }
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; }