static bool _check_dir_contents( git_buf *dir, const char *sub, bool (*predicate)(const char *)) { bool result; size_t dir_size = git_buf_len(dir); size_t sub_size = strlen(sub); size_t alloc_size; /* leave base valid even if we could not make space for subdir */ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, dir_size, sub_size) || GIT_ADD_SIZET_OVERFLOW(&alloc_size, alloc_size, 2) || git_buf_try_grow(dir, alloc_size, false, false) < 0) return false; /* save excursion */ git_buf_joinpath(dir, dir->ptr, sub); result = predicate(dir->ptr); /* restore path */ git_buf_truncate(dir, dir_size); return result; }
static int diriter_update_paths(git_path_diriter *diriter) { size_t filename_len, path_len; filename_len = wcslen(diriter->current.cFileName); if (GIT_ADD_SIZET_OVERFLOW(&path_len, diriter->parent_len, filename_len) || GIT_ADD_SIZET_OVERFLOW(&path_len, path_len, 2)) return -1; if (path_len > GIT_WIN_PATH_UTF16) { giterr_set(GITERR_FILESYSTEM, "invalid path '%.*ls\\%ls' (path too long)", diriter->parent_len, diriter->path, diriter->current.cFileName); return -1; } diriter->path[diriter->parent_len] = L'\\'; memcpy(&diriter->path[diriter->parent_len+1], diriter->current.cFileName, filename_len * sizeof(wchar_t)); diriter->path[path_len-1] = L'\0'; git_buf_truncate(&diriter->path_utf8, diriter->parent_utf8_len); git_buf_putc(&diriter->path_utf8, '/'); git_buf_put_w(&diriter->path_utf8, diriter->current.cFileName, filename_len); if (git_buf_oom(&diriter->path_utf8)) return -1; return 0; }
static git_reference *alloc_ref(const char *name) { git_reference *ref = NULL; size_t namelen = strlen(name), reflen; if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && (ref = git__calloc(1, reflen)) != NULL) memcpy(ref->name, name, namelen + 1); return ref; }
git_reference *git_reference__set_name( git_reference *ref, const char *name) { size_t namelen = strlen(name); size_t reflen; git_reference *rewrite = NULL; if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) && !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) && (rewrite = git__realloc(ref, reflen)) != NULL) memcpy(rewrite->name, name, namelen + 1); return rewrite; }
static int parse_header( obj_hdr *out, size_t *out_len, const unsigned char *_data, size_t data_len) { const char *data = (char *)_data; size_t i, typename_len, size_idx, size_len; int64_t size; *out_len = 0; /* find the object type name */ for (i = 0, typename_len = 0; i < data_len; i++, typename_len++) { if (data[i] == ' ') break; } if (typename_len == data_len) goto on_error; out->type = git_object_stringn2type(data, typename_len); size_idx = typename_len + 1; for (i = size_idx, size_len = 0; i < data_len; i++, size_len++) { if (data[i] == '\0') break; } if (i == data_len) goto on_error; if (git__strntol64(&size, &data[size_idx], size_len, NULL, 10) < 0 || size < 0) goto on_error; if ((uint64_t)size > SIZE_MAX) { giterr_set(GITERR_OBJECT, "object is larger than available memory"); return -1; } out->size = size; if (GIT_ADD_SIZET_OVERFLOW(out_len, i, 1)) goto on_error; return 0; on_error: giterr_set(GITERR_OBJECT, "failed to parse loose object: invalid header"); return -1; }
/* * At one point, there was a loose object format that was intended to * mimic the format used in pack-files. This was to allow easy copying * of loose object data into packs. This format is no longer used, but * we must still read it. */ static int read_loose_packlike(git_rawobj *out, git_buf *obj) { git_buf body = GIT_BUF_INIT; const unsigned char *obj_data; obj_hdr hdr; size_t obj_len, head_len, alloc_size; int error; obj_data = (unsigned char *)obj->ptr; obj_len = obj->size; /* * read the object header, which is an (uncompressed) * binary encoding of the object type and size. */ if ((error = parse_header_packlike(&hdr, &head_len, obj_data, obj_len)) < 0) goto done; if (!git_object_typeisloose(hdr.type) || head_len > obj_len) { giterr_set(GITERR_ODB, "failed to inflate loose object"); error = -1; goto done; } obj_data += head_len; obj_len -= head_len; /* * allocate a buffer and inflate the data into it */ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) || git_buf_init(&body, alloc_size) < 0) { error = -1; goto done; } if ((error = git_zstream_inflatebuf(&body, obj_data, obj_len)) < 0) goto done; out->len = hdr.size; out->type = hdr.type; out->data = git_buf_detach(&body); done: git_buf_dispose(&body); return error; }
/* '\"' -> '"' etc */ static int unescape_line( char **out, bool *is_multi, const char *ptr, int quote_count) { char *str, *fixed, *esc; size_t ptr_len = strlen(ptr), alloc_len; *is_multi = false; if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, ptr_len, 1) || (str = git__malloc(alloc_len)) == NULL) { return -1; } fixed = str; while (*ptr != '\0') { if (*ptr == '"') { quote_count++; } else if (*ptr != '\\') { *fixed++ = *ptr; } else { /* backslash, check the next char */ ptr++; /* if we're at the end, it's a multiline, so keep the backslash */ if (*ptr == '\0') { *is_multi = true; goto done; } if ((esc = strchr(git_config_escapes, *ptr)) != NULL) { *fixed++ = git_config_escaped[esc - git_config_escapes]; } else { git__free(str); giterr_set(GITERR_CONFIG, "invalid escape at %s", ptr); return -1; } } ptr++; } done: *fixed = '\0'; *out = str; return 0; }
static int read_loose_standard(git_rawobj *out, git_buf *obj) { git_zstream zstream = GIT_ZSTREAM_INIT; unsigned char head[MAX_HEADER_LEN], *body = NULL; size_t decompressed, head_len, body_len, alloc_size; obj_hdr hdr; int error; if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0 || (error = git_zstream_set_input(&zstream, git_buf_cstr(obj), git_buf_len(obj))) < 0) goto done; decompressed = sizeof(head); /* * inflate the initial part of the compressed buffer in order to * parse the header; read the largest header possible, then push the * remainder into the body buffer. */ if ((error = git_zstream_get_output(head, &decompressed, &zstream)) < 0 || (error = parse_header(&hdr, &head_len, head, decompressed)) < 0) goto done; if (!git_object_typeisloose(hdr.type)) { giterr_set(GITERR_ODB, "failed to inflate disk object"); error = -1; goto done; } /* * allocate a buffer and inflate the object data into it * (including the initial sequence in the head buffer). */ if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) || (body = git__malloc(alloc_size)) == NULL) { error = -1; goto done; } assert(decompressed >= head_len); body_len = decompressed - head_len; if (body_len) memcpy(body, head + head_len, body_len); decompressed = hdr.size - body_len; if ((error = git_zstream_get_output(body + body_len, &decompressed, &zstream)) < 0) goto done; if (!git_zstream_done(&zstream)) { giterr_set(GITERR_ZLIB, "failed to finish zlib inflation: stream aborted prematurely"); error = -1; goto done; } body[hdr.size] = '\0'; out->data = body; out->len = hdr.size; out->type = hdr.type; done: if (error < 0) git__free(body); git_zstream_free(&zstream); return error; }