| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | /* | 
| 2 |  |  |  |  |  |  | * Copyright (C) the libgit2 contributors. All rights reserved. | 
| 3 |  |  |  |  |  |  | * | 
| 4 |  |  |  |  |  |  | * This file is part of libgit2, distributed under the GNU GPL v2 with | 
| 5 |  |  |  |  |  |  | * a Linking Exception. For full terms see the included COPYING file. | 
| 6 |  |  |  |  |  |  | */ | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | #include "odb.h" | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | #include | 
| 11 |  |  |  |  |  |  | #include "git2/object.h" | 
| 12 |  |  |  |  |  |  | #include "git2/sys/odb_backend.h" | 
| 13 |  |  |  |  |  |  | #include "futils.h" | 
| 14 |  |  |  |  |  |  | #include "hash.h" | 
| 15 |  |  |  |  |  |  | #include "delta.h" | 
| 16 |  |  |  |  |  |  | #include "filter.h" | 
| 17 |  |  |  |  |  |  | #include "repository.h" | 
| 18 |  |  |  |  |  |  | #include "blob.h" | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | #include "git2/odb_backend.h" | 
| 21 |  |  |  |  |  |  | #include "git2/oid.h" | 
| 22 |  |  |  |  |  |  | #include "git2/oidarray.h" | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | #define GIT_ALTERNATES_FILE "info/alternates" | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | /* | 
| 27 |  |  |  |  |  |  | * We work under the assumption that most objects for long-running | 
| 28 |  |  |  |  |  |  | * operations will be packed | 
| 29 |  |  |  |  |  |  | */ | 
| 30 |  |  |  |  |  |  | #define GIT_LOOSE_PRIORITY 1 | 
| 31 |  |  |  |  |  |  | #define GIT_PACKED_PRIORITY 2 | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | #define GIT_ALTERNATES_MAX_DEPTH 5 | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | bool git_odb__strict_hash_verification = true; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | typedef struct | 
| 38 |  |  |  |  |  |  | { | 
| 39 |  |  |  |  |  |  | git_odb_backend *backend; | 
| 40 |  |  |  |  |  |  | int priority; | 
| 41 |  |  |  |  |  |  | bool is_alternate; | 
| 42 |  |  |  |  |  |  | ino_t disk_inode; | 
| 43 |  |  |  |  |  |  | } backend_internal; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 1950 |  |  |  |  |  | static git_cache *odb_cache(git_odb *odb) | 
| 46 |  |  |  |  |  |  | { | 
| 47 | 1950 | 50 |  |  |  |  | if (odb->rc.owner != NULL) { | 
| 48 | 1950 |  |  |  |  |  | git_repository *owner = odb->rc.owner; | 
| 49 | 1950 |  |  |  |  |  | return &owner->objects; | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 0 |  |  |  |  |  | return &odb->own_cache; | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id); | 
| 56 |  |  |  |  |  |  | static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); | 
| 57 |  |  |  |  |  |  | static int error_null_oid(int error, const char *message); | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 1045 |  |  |  |  |  | static git_object_t odb_hardcoded_type(const git_oid *id) | 
| 60 |  |  |  |  |  |  | { | 
| 61 |  |  |  |  |  |  | static git_oid empty_tree = {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, | 
| 62 |  |  |  |  |  |  | 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }}; | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 1045 | 100 |  |  |  |  | if (!git_oid_cmp(id, &empty_tree)) | 
| 65 | 1 |  |  |  |  |  | return GIT_OBJECT_TREE; | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 1044 |  |  |  |  |  | return GIT_OBJECT_INVALID; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 649 |  |  |  |  |  | static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id) | 
| 71 |  |  |  |  |  |  | { | 
| 72 |  |  |  |  |  |  | git_object_t type; | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 649 |  |  |  |  |  | *found = false; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 649 | 100 |  |  |  |  | if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID) | 
| 77 | 648 |  |  |  |  |  | return 0; | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 1 |  |  |  |  |  | raw->type = type; | 
| 80 | 1 |  |  |  |  |  | raw->len = 0; | 
| 81 | 1 |  |  |  |  |  | raw->data = git__calloc(1, sizeof(uint8_t)); | 
| 82 | 1 | 50 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(raw->data); | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 1 |  |  |  |  |  | *found = true; | 
| 85 | 1 |  |  |  |  |  | return 0; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 1403 |  |  |  |  |  | int git_odb__format_object_header( | 
| 89 |  |  |  |  |  |  | size_t *written, | 
| 90 |  |  |  |  |  |  | char *hdr, | 
| 91 |  |  |  |  |  |  | size_t hdr_size, | 
| 92 |  |  |  |  |  |  | git_object_size_t obj_len, | 
| 93 |  |  |  |  |  |  | git_object_t obj_type) | 
| 94 |  |  |  |  |  |  | { | 
| 95 | 1403 |  |  |  |  |  | const char *type_str = git_object_type2string(obj_type); | 
| 96 | 1403 | 50 |  |  |  |  | int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size; | 
| 97 |  |  |  |  |  |  | int len; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 1403 |  |  |  |  |  | len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len); | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 1403 | 50 |  |  |  |  | if (len < 0 || len >= hdr_max) { | 
|  |  | 50 |  |  |  |  |  | 
| 102 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_OS, "object header creation failed"); | 
| 103 | 0 |  |  |  |  |  | return -1; | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 1403 |  |  |  |  |  | *written = (size_t)(len + 1); | 
| 107 | 1403 |  |  |  |  |  | return 0; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 994 |  |  |  |  |  | int git_odb__hashobj(git_oid *id, git_rawobj *obj) | 
| 111 |  |  |  |  |  |  | { | 
| 112 |  |  |  |  |  |  | git_buf_vec vec[2]; | 
| 113 |  |  |  |  |  |  | char header[64]; | 
| 114 |  |  |  |  |  |  | size_t hdrlen; | 
| 115 |  |  |  |  |  |  | int error; | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 994 | 50 |  |  |  |  | assert(id && obj); | 
|  |  | 50 |  |  |  |  |  | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 994 | 50 |  |  |  |  | if (!git_object_typeisloose(obj->type)) { | 
| 120 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, "invalid object type"); | 
| 121 | 0 |  |  |  |  |  | return -1; | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 994 | 50 |  |  |  |  | if (!obj->data && obj->len != 0) { | 
|  |  | 0 |  |  |  |  |  | 
| 125 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, "invalid object"); | 
| 126 | 0 |  |  |  |  |  | return -1; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 994 | 50 |  |  |  |  | if ((error = git_odb__format_object_header(&hdrlen, | 
| 130 |  |  |  |  |  |  | header, sizeof(header), obj->len, obj->type)) < 0) | 
| 131 | 0 |  |  |  |  |  | return error; | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 994 |  |  |  |  |  | vec[0].data = header; | 
| 134 | 994 |  |  |  |  |  | vec[0].len = hdrlen; | 
| 135 | 994 |  |  |  |  |  | vec[1].data = obj->data; | 
| 136 | 994 |  |  |  |  |  | vec[1].len = obj->len; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 994 |  |  |  |  |  | return git_hash_vec(id, vec, 2); | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  |  | 
| 142 | 776 |  |  |  |  |  | static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source) | 
| 143 |  |  |  |  |  |  | { | 
| 144 | 776 |  |  |  |  |  | git_odb_object *object = git__calloc(1, sizeof(git_odb_object)); | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 776 | 50 |  |  |  |  | if (object != NULL) { | 
| 147 | 776 |  |  |  |  |  | git_oid_cpy(&object->cached.oid, oid); | 
| 148 | 776 |  |  |  |  |  | object->cached.type = source->type; | 
| 149 | 776 |  |  |  |  |  | object->cached.size = source->len; | 
| 150 | 776 |  |  |  |  |  | object->buffer      = source->data; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 776 |  |  |  |  |  | return object; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 774 |  |  |  |  |  | void git_odb_object__free(void *object) | 
| 157 |  |  |  |  |  |  | { | 
| 158 | 774 | 50 |  |  |  |  | if (object != NULL) { | 
| 159 | 774 |  |  |  |  |  | git__free(((git_odb_object *)object)->buffer); | 
| 160 | 774 |  |  |  |  |  | git__free(object); | 
| 161 |  |  |  |  |  |  | } | 
| 162 | 774 |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 1 |  |  |  |  |  | const git_oid *git_odb_object_id(git_odb_object *object) | 
| 165 |  |  |  |  |  |  | { | 
| 166 | 1 |  |  |  |  |  | return &object->cached.oid; | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 638 |  |  |  |  |  | const void *git_odb_object_data(git_odb_object *object) | 
| 170 |  |  |  |  |  |  | { | 
| 171 | 638 |  |  |  |  |  | return object->buffer; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 646 |  |  |  |  |  | size_t git_odb_object_size(git_odb_object *object) | 
| 175 |  |  |  |  |  |  | { | 
| 176 | 646 |  |  |  |  |  | return object->cached.size; | 
| 177 |  |  |  |  |  |  | } | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 51 |  |  |  |  |  | git_object_t git_odb_object_type(git_odb_object *object) | 
| 180 |  |  |  |  |  |  | { | 
| 181 | 51 |  |  |  |  |  | return object->cached.type; | 
| 182 |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 101 |  |  |  |  |  | int git_odb_object_dup(git_odb_object **dest, git_odb_object *source) | 
| 185 |  |  |  |  |  |  | { | 
| 186 | 101 |  |  |  |  |  | git_cached_obj_incref(source); | 
| 187 | 101 |  |  |  |  |  | *dest = source; | 
| 188 | 101 |  |  |  |  |  | return 0; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 1076 |  |  |  |  |  | void git_odb_object_free(git_odb_object *object) | 
| 192 |  |  |  |  |  |  | { | 
| 193 | 1076 | 100 |  |  |  |  | if (object == NULL) | 
| 194 | 3 |  |  |  |  |  | return; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 1073 |  |  |  |  |  | git_cached_obj_decref(object); | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  |  | 
| 199 | 126 |  |  |  |  |  | int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type) | 
| 200 |  |  |  |  |  |  | { | 
| 201 |  |  |  |  |  |  | size_t hdr_len; | 
| 202 |  |  |  |  |  |  | char hdr[64], buffer[FILEIO_BUFSIZE]; | 
| 203 |  |  |  |  |  |  | git_hash_ctx ctx; | 
| 204 | 126 |  |  |  |  |  | ssize_t read_len = 0; | 
| 205 | 126 |  |  |  |  |  | int error = 0; | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 126 | 50 |  |  |  |  | if (!git_object_typeisloose(type)) { | 
| 208 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_INVALID, "invalid object type for hash"); | 
| 209 | 0 |  |  |  |  |  | return -1; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 126 | 50 |  |  |  |  | if ((error = git_hash_ctx_init(&ctx)) < 0) | 
| 213 | 0 |  |  |  |  |  | return error; | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 126 | 50 |  |  |  |  | if ((error = git_odb__format_object_header(&hdr_len, hdr, | 
| 216 |  |  |  |  |  |  | sizeof(hdr), size, type)) < 0) | 
| 217 | 0 |  |  |  |  |  | goto done; | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 126 | 50 |  |  |  |  | if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0) | 
| 220 | 0 |  |  |  |  |  | goto done; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 235 | 100 |  |  |  |  | while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { | 
|  |  | 50 |  |  |  |  |  | 
| 223 | 109 | 50 |  |  |  |  | if ((error = git_hash_update(&ctx, buffer, read_len)) < 0) | 
| 224 | 0 |  |  |  |  |  | goto done; | 
| 225 |  |  |  |  |  |  |  | 
| 226 | 109 |  |  |  |  |  | size -= read_len; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | /* If p_read returned an error code, the read obviously failed. | 
| 230 |  |  |  |  |  |  | * If size is not zero, the file was truncated after we originally | 
| 231 |  |  |  |  |  |  | * stat'd it, so we consider this a read failure too */ | 
| 232 | 126 | 50 |  |  |  |  | if (read_len < 0 || size > 0) { | 
|  |  | 50 |  |  |  |  |  | 
| 233 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_OS, "error reading file for hashing"); | 
| 234 | 0 |  |  |  |  |  | error = -1; | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 0 |  |  |  |  |  | goto done; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 | 126 |  |  |  |  |  | error = git_hash_final(out, &ctx); | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | done: | 
| 242 | 126 |  |  |  |  |  | git_hash_ctx_cleanup(&ctx); | 
| 243 | 126 |  |  |  |  |  | return error; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  |  | 
| 246 | 165 |  |  |  |  |  | int git_odb__hashfd_filtered( | 
| 247 |  |  |  |  |  |  | git_oid *out, git_file fd, size_t size, git_object_t type, git_filter_list *fl) | 
| 248 |  |  |  |  |  |  | { | 
| 249 |  |  |  |  |  |  | int error; | 
| 250 | 165 |  |  |  |  |  | git_buf raw = GIT_BUF_INIT; | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 165 | 100 |  |  |  |  | if (!fl) | 
| 253 | 126 |  |  |  |  |  | return git_odb__hashfd(out, fd, size, type); | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | /* size of data is used in header, so we have to read the whole file | 
| 256 |  |  |  |  |  |  | * into memory to apply filters before beginning to calculate the hash | 
| 257 |  |  |  |  |  |  | */ | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 39 | 50 |  |  |  |  | if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) { | 
| 260 | 39 |  |  |  |  |  | git_buf post = GIT_BUF_INIT; | 
| 261 |  |  |  |  |  |  |  | 
| 262 | 39 |  |  |  |  |  | error = git_filter_list_apply_to_data(&post, fl, &raw); | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 39 |  |  |  |  |  | git_buf_dispose(&raw); | 
| 265 |  |  |  |  |  |  |  | 
| 266 | 39 | 50 |  |  |  |  | if (!error) | 
| 267 | 39 |  |  |  |  |  | error = git_odb_hash(out, post.ptr, post.size, type); | 
| 268 |  |  |  |  |  |  |  | 
| 269 | 39 |  |  |  |  |  | git_buf_dispose(&post); | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  |  | 
| 272 | 165 |  |  |  |  |  | return error; | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 | 0 |  |  |  |  |  | int git_odb__hashlink(git_oid *out, const char *path) | 
| 276 |  |  |  |  |  |  | { | 
| 277 |  |  |  |  |  |  | struct stat st; | 
| 278 |  |  |  |  |  |  | int size; | 
| 279 |  |  |  |  |  |  | int result; | 
| 280 |  |  |  |  |  |  |  | 
| 281 | 0 | 0 |  |  |  |  | if (git_path_lstat(path, &st) < 0) | 
| 282 | 0 |  |  |  |  |  | return -1; | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 0 | 0 |  |  |  |  | if (!git__is_int(st.st_size) || (int)st.st_size < 0) { | 
|  |  | 0 |  |  |  |  |  | 
| 285 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_FILESYSTEM, "file size overflow for 32-bit systems"); | 
| 286 | 0 |  |  |  |  |  | return -1; | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 0 |  |  |  |  |  | size = (int)st.st_size; | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 0 | 0 |  |  |  |  | if (S_ISLNK(st.st_mode)) { | 
| 292 |  |  |  |  |  |  | char *link_data; | 
| 293 |  |  |  |  |  |  | int read_len; | 
| 294 |  |  |  |  |  |  | size_t alloc_size; | 
| 295 |  |  |  |  |  |  |  | 
| 296 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, size, 1); | 
|  |  | 0 |  |  |  |  |  | 
| 297 | 0 |  |  |  |  |  | link_data = git__malloc(alloc_size); | 
| 298 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(link_data); | 
| 299 |  |  |  |  |  |  |  | 
| 300 | 0 |  |  |  |  |  | read_len = p_readlink(path, link_data, size); | 
| 301 | 0 |  |  |  |  |  | link_data[size] = '\0'; | 
| 302 | 0 | 0 |  |  |  |  | if (read_len != size) { | 
| 303 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path); | 
| 304 | 0 |  |  |  |  |  | git__free(link_data); | 
| 305 | 0 |  |  |  |  |  | return -1; | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  |  | 
| 308 | 0 |  |  |  |  |  | result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB); | 
| 309 | 0 |  |  |  |  |  | git__free(link_data); | 
| 310 |  |  |  |  |  |  | } else { | 
| 311 | 0 |  |  |  |  |  | int fd = git_futils_open_ro(path); | 
| 312 | 0 | 0 |  |  |  |  | if (fd < 0) | 
| 313 | 0 |  |  |  |  |  | return -1; | 
| 314 | 0 |  |  |  |  |  | result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB); | 
| 315 | 0 |  |  |  |  |  | p_close(fd); | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 | 0 |  |  |  |  |  | return result; | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | 
| 321 | 0 |  |  |  |  |  | int git_odb_hashfile(git_oid *out, const char *path, git_object_t type) | 
| 322 |  |  |  |  |  |  | { | 
| 323 |  |  |  |  |  |  | uint64_t size; | 
| 324 | 0 |  |  |  |  |  | int fd, error = 0; | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 0 | 0 |  |  |  |  | if ((fd = git_futils_open_ro(path)) < 0) | 
| 327 | 0 |  |  |  |  |  | return fd; | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 0 | 0 |  |  |  |  | if ((error = git_futils_filesize(&size, fd)) < 0) | 
| 330 | 0 |  |  |  |  |  | goto done; | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 0 | 0 |  |  |  |  | if (!git__is_sizet(size)) { | 
| 333 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems"); | 
| 334 | 0 |  |  |  |  |  | error = -1; | 
| 335 | 0 |  |  |  |  |  | goto done; | 
| 336 |  |  |  |  |  |  | } | 
| 337 |  |  |  |  |  |  |  | 
| 338 | 0 |  |  |  |  |  | error = git_odb__hashfd(out, fd, (size_t)size, type); | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | done: | 
| 341 | 0 |  |  |  |  |  | p_close(fd); | 
| 342 | 0 |  |  |  |  |  | return error; | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 992 |  |  |  |  |  | int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type) | 
| 346 |  |  |  |  |  |  | { | 
| 347 |  |  |  |  |  |  | git_rawobj raw; | 
| 348 |  |  |  |  |  |  |  | 
| 349 | 992 | 50 |  |  |  |  | assert(id); | 
| 350 |  |  |  |  |  |  |  | 
| 351 | 992 |  |  |  |  |  | raw.data = (void *)data; | 
| 352 | 992 |  |  |  |  |  | raw.len = len; | 
| 353 | 992 |  |  |  |  |  | raw.type = type; | 
| 354 |  |  |  |  |  |  |  | 
| 355 | 992 |  |  |  |  |  | return git_odb__hashobj(id, &raw); | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | /** | 
| 359 |  |  |  |  |  |  | * FAKE WSTREAM | 
| 360 |  |  |  |  |  |  | */ | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | typedef struct { | 
| 363 |  |  |  |  |  |  | git_odb_stream stream; | 
| 364 |  |  |  |  |  |  | char *buffer; | 
| 365 |  |  |  |  |  |  | size_t size, written; | 
| 366 |  |  |  |  |  |  | git_object_t type; | 
| 367 |  |  |  |  |  |  | } fake_wstream; | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 0 |  |  |  |  |  | static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid) | 
| 370 |  |  |  |  |  |  | { | 
| 371 | 0 |  |  |  |  |  | fake_wstream *stream = (fake_wstream *)_stream; | 
| 372 | 0 |  |  |  |  |  | return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type); | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 0 |  |  |  |  |  | static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len) | 
| 376 |  |  |  |  |  |  | { | 
| 377 | 0 |  |  |  |  |  | fake_wstream *stream = (fake_wstream *)_stream; | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 0 | 0 |  |  |  |  | assert(stream->written + len <= stream->size); | 
| 380 |  |  |  |  |  |  |  | 
| 381 | 0 |  |  |  |  |  | memcpy(stream->buffer + stream->written, data, len); | 
| 382 | 0 |  |  |  |  |  | stream->written += len; | 
| 383 | 0 |  |  |  |  |  | return 0; | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 0 |  |  |  |  |  | static void fake_wstream__free(git_odb_stream *_stream) | 
| 387 |  |  |  |  |  |  | { | 
| 388 | 0 |  |  |  |  |  | fake_wstream *stream = (fake_wstream *)_stream; | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 0 |  |  |  |  |  | git__free(stream->buffer); | 
| 391 | 0 |  |  |  |  |  | git__free(stream); | 
| 392 | 0 |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  |  | 
| 394 | 0 |  |  |  |  |  | static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_object_size_t size, git_object_t type) | 
| 395 |  |  |  |  |  |  | { | 
| 396 |  |  |  |  |  |  | fake_wstream *stream; | 
| 397 |  |  |  |  |  |  | size_t blobsize; | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_BLOBSIZE(size); | 
| 400 | 0 |  |  |  |  |  | blobsize = (size_t)size; | 
| 401 |  |  |  |  |  |  |  | 
| 402 | 0 |  |  |  |  |  | stream = git__calloc(1, sizeof(fake_wstream)); | 
| 403 | 0 | 0 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(stream); | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 0 |  |  |  |  |  | stream->size = blobsize; | 
| 406 | 0 |  |  |  |  |  | stream->type = type; | 
| 407 | 0 |  |  |  |  |  | stream->buffer = git__malloc(blobsize); | 
| 408 | 0 | 0 |  |  |  |  | if (stream->buffer == NULL) { | 
| 409 | 0 |  |  |  |  |  | git__free(stream); | 
| 410 | 0 |  |  |  |  |  | return -1; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 | 0 |  |  |  |  |  | stream->stream.backend = backend; | 
| 414 | 0 |  |  |  |  |  | stream->stream.read = NULL; /* read only */ | 
| 415 | 0 |  |  |  |  |  | stream->stream.write = &fake_wstream__write; | 
| 416 | 0 |  |  |  |  |  | stream->stream.finalize_write = &fake_wstream__fwrite; | 
| 417 | 0 |  |  |  |  |  | stream->stream.free = &fake_wstream__free; | 
| 418 | 0 |  |  |  |  |  | stream->stream.mode = GIT_STREAM_WRONLY; | 
| 419 |  |  |  |  |  |  |  | 
| 420 | 0 |  |  |  |  |  | *stream_p = (git_odb_stream *)stream; | 
| 421 | 0 |  |  |  |  |  | return 0; | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | /*********************************************************** | 
| 425 |  |  |  |  |  |  | * | 
| 426 |  |  |  |  |  |  | * OBJECT DATABASE PUBLIC API | 
| 427 |  |  |  |  |  |  | * | 
| 428 |  |  |  |  |  |  | * Public calls for the ODB functionality | 
| 429 |  |  |  |  |  |  | * | 
| 430 |  |  |  |  |  |  | ***********************************************************/ | 
| 431 |  |  |  |  |  |  |  | 
| 432 | 79 |  |  |  |  |  | static int backend_sort_cmp(const void *a, const void *b) | 
| 433 |  |  |  |  |  |  | { | 
| 434 | 79 |  |  |  |  |  | const backend_internal *backend_a = (const backend_internal *)(a); | 
| 435 | 79 |  |  |  |  |  | const backend_internal *backend_b = (const backend_internal *)(b); | 
| 436 |  |  |  |  |  |  |  | 
| 437 | 79 | 100 |  |  |  |  | if (backend_b->priority == backend_a->priority) { | 
| 438 | 1 | 50 |  |  |  |  | if (backend_a->is_alternate) | 
| 439 | 0 |  |  |  |  |  | return -1; | 
| 440 | 1 | 50 |  |  |  |  | if (backend_b->is_alternate) | 
| 441 | 1 |  |  |  |  |  | return 1; | 
| 442 | 0 |  |  |  |  |  | return 0; | 
| 443 |  |  |  |  |  |  | } | 
| 444 | 78 |  |  |  |  |  | return (backend_b->priority - backend_a->priority); | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  |  | 
| 447 | 36 |  |  |  |  |  | int git_odb_new(git_odb **out) | 
| 448 |  |  |  |  |  |  | { | 
| 449 | 36 |  |  |  |  |  | git_odb *db = git__calloc(1, sizeof(*db)); | 
| 450 | 36 | 50 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(db); | 
| 451 |  |  |  |  |  |  |  | 
| 452 | 36 | 50 |  |  |  |  | if (git_cache_init(&db->own_cache) < 0) { | 
| 453 | 0 |  |  |  |  |  | git__free(db); | 
| 454 | 0 |  |  |  |  |  | return -1; | 
| 455 |  |  |  |  |  |  | } | 
| 456 | 36 | 50 |  |  |  |  | if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { | 
| 457 | 0 |  |  |  |  |  | git_cache_dispose(&db->own_cache); | 
| 458 | 0 |  |  |  |  |  | git__free(db); | 
| 459 | 0 |  |  |  |  |  | return -1; | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  |  | 
| 462 | 36 |  |  |  |  |  | *out = db; | 
| 463 | 36 |  |  |  |  |  | GIT_REFCOUNT_INC(db); | 
| 464 | 36 |  |  |  |  |  | return 0; | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 | 74 |  |  |  |  |  | static int add_backend_internal( | 
| 468 |  |  |  |  |  |  | git_odb *odb, git_odb_backend *backend, | 
| 469 |  |  |  |  |  |  | int priority, bool is_alternate, ino_t disk_inode) | 
| 470 |  |  |  |  |  |  | { | 
| 471 |  |  |  |  |  |  | backend_internal *internal; | 
| 472 |  |  |  |  |  |  |  | 
| 473 | 74 | 50 |  |  |  |  | assert(odb && backend); | 
|  |  | 50 |  |  |  |  |  | 
| 474 |  |  |  |  |  |  |  | 
| 475 | 74 | 50 |  |  |  |  | GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend"); | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | /* Check if the backend is already owned by another ODB */ | 
| 478 | 74 | 50 |  |  |  |  | assert(!backend->odb || backend->odb == odb); | 
|  |  | 0 |  |  |  |  |  | 
| 479 |  |  |  |  |  |  |  | 
| 480 | 74 |  |  |  |  |  | internal = git__malloc(sizeof(backend_internal)); | 
| 481 | 74 | 50 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(internal); | 
| 482 |  |  |  |  |  |  |  | 
| 483 | 74 |  |  |  |  |  | internal->backend = backend; | 
| 484 | 74 |  |  |  |  |  | internal->priority = priority; | 
| 485 | 74 |  |  |  |  |  | internal->is_alternate = is_alternate; | 
| 486 | 74 |  |  |  |  |  | internal->disk_inode = disk_inode; | 
| 487 |  |  |  |  |  |  |  | 
| 488 | 74 | 50 |  |  |  |  | if (git_vector_insert(&odb->backends, internal) < 0) { | 
| 489 | 0 |  |  |  |  |  | git__free(internal); | 
| 490 | 0 |  |  |  |  |  | return -1; | 
| 491 |  |  |  |  |  |  | } | 
| 492 |  |  |  |  |  |  |  | 
| 493 | 74 |  |  |  |  |  | git_vector_sort(&odb->backends); | 
| 494 | 74 |  |  |  |  |  | internal->backend->odb = odb; | 
| 495 | 74 |  |  |  |  |  | return 0; | 
| 496 |  |  |  |  |  |  | } | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 3 |  |  |  |  |  | int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) | 
| 499 |  |  |  |  |  |  | { | 
| 500 | 3 |  |  |  |  |  | return add_backend_internal(odb, backend, priority, false, 0); | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 | 1 |  |  |  |  |  | int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) | 
| 504 |  |  |  |  |  |  | { | 
| 505 | 1 |  |  |  |  |  | return add_backend_internal(odb, backend, priority, true, 0); | 
| 506 |  |  |  |  |  |  | } | 
| 507 |  |  |  |  |  |  |  | 
| 508 | 7 |  |  |  |  |  | size_t git_odb_num_backends(git_odb *odb) | 
| 509 |  |  |  |  |  |  | { | 
| 510 | 7 | 50 |  |  |  |  | assert(odb); | 
| 511 | 7 |  |  |  |  |  | return odb->backends.length; | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  |  | 
| 514 | 0 |  |  |  |  |  | static int git_odb__error_unsupported_in_backend(const char *action) | 
| 515 |  |  |  |  |  |  | { | 
| 516 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, | 
| 517 |  |  |  |  |  |  | "cannot %s - unsupported in the loaded odb backends", action); | 
| 518 | 0 |  |  |  |  |  | return -1; | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  |  | 
| 522 | 0 |  |  |  |  |  | int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) | 
| 523 |  |  |  |  |  |  | { | 
| 524 |  |  |  |  |  |  | backend_internal *internal; | 
| 525 |  |  |  |  |  |  |  | 
| 526 | 0 | 0 |  |  |  |  | assert(out && odb); | 
|  |  | 0 |  |  |  |  |  | 
| 527 | 0 |  |  |  |  |  | internal = git_vector_get(&odb->backends, pos); | 
| 528 |  |  |  |  |  |  |  | 
| 529 | 0 | 0 |  |  |  |  | if (internal && internal->backend) { | 
|  |  | 0 |  |  |  |  |  | 
| 530 | 0 |  |  |  |  |  | *out = internal->backend; | 
| 531 | 0 |  |  |  |  |  | return 0; | 
| 532 |  |  |  |  |  |  | } | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos); | 
| 535 | 0 |  |  |  |  |  | return GIT_ENOTFOUND; | 
| 536 |  |  |  |  |  |  | } | 
| 537 |  |  |  |  |  |  |  | 
| 538 | 35 |  |  |  |  |  | int git_odb__add_default_backends( | 
| 539 |  |  |  |  |  |  | git_odb *db, const char *objects_dir, | 
| 540 |  |  |  |  |  |  | bool as_alternates, int alternate_depth) | 
| 541 |  |  |  |  |  |  | { | 
| 542 |  |  |  |  |  |  | size_t i; | 
| 543 |  |  |  |  |  |  | struct stat st; | 
| 544 |  |  |  |  |  |  | ino_t inode; | 
| 545 |  |  |  |  |  |  | git_odb_backend *loose, *packed; | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | /* TODO: inodes are not really relevant on Win32, so we need to find | 
| 548 |  |  |  |  |  |  | * a cross-platform workaround for this */ | 
| 549 |  |  |  |  |  |  | #ifdef GIT_WIN32 | 
| 550 |  |  |  |  |  |  | GIT_UNUSED(i); | 
| 551 |  |  |  |  |  |  | GIT_UNUSED(st); | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | inode = 0; | 
| 554 |  |  |  |  |  |  | #else | 
| 555 | 35 | 50 |  |  |  |  | if (p_stat(objects_dir, &st) < 0) { | 
| 556 | 0 | 0 |  |  |  |  | if (as_alternates) | 
| 557 |  |  |  |  |  |  | /* this should warn */ | 
| 558 | 0 |  |  |  |  |  | return 0; | 
| 559 |  |  |  |  |  |  |  | 
| 560 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir); | 
| 561 | 0 |  |  |  |  |  | return -1; | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  |  | 
| 564 | 35 |  |  |  |  |  | inode = st.st_ino; | 
| 565 |  |  |  |  |  |  |  | 
| 566 | 35 | 50 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 567 | 0 |  |  |  |  |  | backend_internal *backend = git_vector_get(&db->backends, i); | 
| 568 | 0 | 0 |  |  |  |  | if (backend->disk_inode == inode) | 
| 569 | 0 |  |  |  |  |  | return 0; | 
| 570 |  |  |  |  |  |  | } | 
| 571 |  |  |  |  |  |  | #endif | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | /* add the loose object backend */ | 
| 574 | 70 |  |  |  |  |  | if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 || | 
| 575 | 35 |  |  |  |  |  | add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) | 
| 576 | 0 |  |  |  |  |  | return -1; | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | /* add the packed file backend */ | 
| 579 | 70 |  |  |  |  |  | if (git_odb_backend_pack(&packed, objects_dir) < 0 || | 
| 580 | 35 |  |  |  |  |  | add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0) | 
| 581 | 0 |  |  |  |  |  | return -1; | 
| 582 |  |  |  |  |  |  |  | 
| 583 | 35 |  |  |  |  |  | return load_alternates(db, objects_dir, alternate_depth); | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 | 35 |  |  |  |  |  | static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth) | 
| 587 |  |  |  |  |  |  | { | 
| 588 | 35 |  |  |  |  |  | git_buf alternates_path = GIT_BUF_INIT; | 
| 589 | 35 |  |  |  |  |  | git_buf alternates_buf = GIT_BUF_INIT; | 
| 590 |  |  |  |  |  |  | char *buffer; | 
| 591 |  |  |  |  |  |  | const char *alternate; | 
| 592 | 35 |  |  |  |  |  | int result = 0; | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | /* Git reports an error, we just ignore anything deeper */ | 
| 595 | 35 | 50 |  |  |  |  | if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH) | 
| 596 | 0 |  |  |  |  |  | return 0; | 
| 597 |  |  |  |  |  |  |  | 
| 598 | 35 | 50 |  |  |  |  | if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0) | 
| 599 | 0 |  |  |  |  |  | return -1; | 
| 600 |  |  |  |  |  |  |  | 
| 601 | 35 | 50 |  |  |  |  | if (git_path_exists(alternates_path.ptr) == false) { | 
| 602 | 35 |  |  |  |  |  | git_buf_dispose(&alternates_path); | 
| 603 | 35 |  |  |  |  |  | return 0; | 
| 604 |  |  |  |  |  |  | } | 
| 605 |  |  |  |  |  |  |  | 
| 606 | 0 | 0 |  |  |  |  | if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) { | 
| 607 | 0 |  |  |  |  |  | git_buf_dispose(&alternates_path); | 
| 608 | 0 |  |  |  |  |  | return -1; | 
| 609 |  |  |  |  |  |  | } | 
| 610 |  |  |  |  |  |  |  | 
| 611 | 0 |  |  |  |  |  | buffer = (char *)alternates_buf.ptr; | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | /* add each alternate as a new backend; one alternate per line */ | 
| 614 | 0 | 0 |  |  |  |  | while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) { | 
| 615 | 0 | 0 |  |  |  |  | if (*alternate == '\0' || *alternate == '#') | 
|  |  | 0 |  |  |  |  |  | 
| 616 | 0 |  |  |  |  |  | continue; | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | /* | 
| 619 |  |  |  |  |  |  | * Relative path: build based on the current `objects` | 
| 620 |  |  |  |  |  |  | * folder. However, relative paths are only allowed in | 
| 621 |  |  |  |  |  |  | * the current repository. | 
| 622 |  |  |  |  |  |  | */ | 
| 623 | 0 | 0 |  |  |  |  | if (*alternate == '.' && !alternate_depth) { | 
|  |  | 0 |  |  |  |  |  | 
| 624 | 0 | 0 |  |  |  |  | if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0) | 
| 625 | 0 |  |  |  |  |  | break; | 
| 626 | 0 |  |  |  |  |  | alternate = git_buf_cstr(&alternates_path); | 
| 627 |  |  |  |  |  |  | } | 
| 628 |  |  |  |  |  |  |  | 
| 629 | 0 | 0 |  |  |  |  | if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) | 
| 630 | 0 |  |  |  |  |  | break; | 
| 631 |  |  |  |  |  |  | } | 
| 632 |  |  |  |  |  |  |  | 
| 633 | 0 |  |  |  |  |  | git_buf_dispose(&alternates_path); | 
| 634 | 0 |  |  |  |  |  | git_buf_dispose(&alternates_buf); | 
| 635 |  |  |  |  |  |  |  | 
| 636 | 35 |  |  |  |  |  | return result; | 
| 637 |  |  |  |  |  |  | } | 
| 638 |  |  |  |  |  |  |  | 
| 639 | 0 |  |  |  |  |  | int git_odb_add_disk_alternate(git_odb *odb, const char *path) | 
| 640 |  |  |  |  |  |  | { | 
| 641 | 0 |  |  |  |  |  | return git_odb__add_default_backends(odb, path, true, 0); | 
| 642 |  |  |  |  |  |  | } | 
| 643 |  |  |  |  |  |  |  | 
| 644 | 2 |  |  |  |  |  | int git_odb_open(git_odb **out, const char *objects_dir) | 
| 645 |  |  |  |  |  |  | { | 
| 646 |  |  |  |  |  |  | git_odb *db; | 
| 647 |  |  |  |  |  |  |  | 
| 648 | 2 | 50 |  |  |  |  | assert(out && objects_dir); | 
|  |  | 50 |  |  |  |  |  | 
| 649 |  |  |  |  |  |  |  | 
| 650 | 2 |  |  |  |  |  | *out = NULL; | 
| 651 |  |  |  |  |  |  |  | 
| 652 | 2 | 50 |  |  |  |  | if (git_odb_new(&db) < 0) | 
| 653 | 0 |  |  |  |  |  | return -1; | 
| 654 |  |  |  |  |  |  |  | 
| 655 | 2 | 50 |  |  |  |  | if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) { | 
| 656 | 0 |  |  |  |  |  | git_odb_free(db); | 
| 657 | 0 |  |  |  |  |  | return -1; | 
| 658 |  |  |  |  |  |  | } | 
| 659 |  |  |  |  |  |  |  | 
| 660 | 2 |  |  |  |  |  | *out = db; | 
| 661 | 2 |  |  |  |  |  | return 0; | 
| 662 |  |  |  |  |  |  | } | 
| 663 |  |  |  |  |  |  |  | 
| 664 | 33 |  |  |  |  |  | int git_odb__set_caps(git_odb *odb, int caps) | 
| 665 |  |  |  |  |  |  | { | 
| 666 | 33 | 50 |  |  |  |  | if (caps == GIT_ODB_CAP_FROM_OWNER) { | 
| 667 | 33 |  |  |  |  |  | git_repository *repo = odb->rc.owner; | 
| 668 |  |  |  |  |  |  | int val; | 
| 669 |  |  |  |  |  |  |  | 
| 670 | 33 | 50 |  |  |  |  | if (!repo) { | 
| 671 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps"); | 
| 672 | 0 |  |  |  |  |  | return -1; | 
| 673 |  |  |  |  |  |  | } | 
| 674 |  |  |  |  |  |  |  | 
| 675 | 33 | 50 |  |  |  |  | if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES)) | 
| 676 | 33 |  |  |  |  |  | odb->do_fsync = !!val; | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  |  | 
| 679 | 33 |  |  |  |  |  | return 0; | 
| 680 |  |  |  |  |  |  | } | 
| 681 |  |  |  |  |  |  |  | 
| 682 | 36 |  |  |  |  |  | static void odb_free(git_odb *db) | 
| 683 |  |  |  |  |  |  | { | 
| 684 |  |  |  |  |  |  | size_t i; | 
| 685 |  |  |  |  |  |  |  | 
| 686 | 110 | 100 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 687 | 74 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 688 | 74 |  |  |  |  |  | git_odb_backend *backend = internal->backend; | 
| 689 |  |  |  |  |  |  |  | 
| 690 | 74 |  |  |  |  |  | backend->free(backend); | 
| 691 |  |  |  |  |  |  |  | 
| 692 | 74 |  |  |  |  |  | git__free(internal); | 
| 693 |  |  |  |  |  |  | } | 
| 694 |  |  |  |  |  |  |  | 
| 695 | 36 |  |  |  |  |  | git_vector_free(&db->backends); | 
| 696 | 36 |  |  |  |  |  | git_cache_dispose(&db->own_cache); | 
| 697 |  |  |  |  |  |  |  | 
| 698 | 36 |  |  |  |  |  | git__memzero(db, sizeof(*db)); | 
| 699 | 36 |  |  |  |  |  | git__free(db); | 
| 700 | 36 |  |  |  |  |  | } | 
| 701 |  |  |  |  |  |  |  | 
| 702 | 212 |  |  |  |  |  | void git_odb_free(git_odb *db) | 
| 703 |  |  |  |  |  |  | { | 
| 704 | 212 | 100 |  |  |  |  | if (db == NULL) | 
| 705 | 10 |  |  |  |  |  | return; | 
| 706 |  |  |  |  |  |  |  | 
| 707 | 202 | 100 |  |  |  |  | GIT_REFCOUNT_DEC(db, odb_free); | 
|  |  | 50 |  |  |  |  |  | 
| 708 |  |  |  |  |  |  | } | 
| 709 |  |  |  |  |  |  |  | 
| 710 | 4 |  |  |  |  |  | static int odb_exists_1( | 
| 711 |  |  |  |  |  |  | git_odb *db, | 
| 712 |  |  |  |  |  |  | const git_oid *id, | 
| 713 |  |  |  |  |  |  | bool only_refreshed) | 
| 714 |  |  |  |  |  |  | { | 
| 715 |  |  |  |  |  |  | size_t i; | 
| 716 | 4 |  |  |  |  |  | bool found = false; | 
| 717 |  |  |  |  |  |  |  | 
| 718 | 12 | 100 |  |  |  |  | for (i = 0; i < db->backends.length && !found; ++i) { | 
|  |  | 50 |  |  |  |  |  | 
| 719 | 8 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 720 | 8 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 721 |  |  |  |  |  |  |  | 
| 722 | 8 | 50 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 0 |  |  |  |  |  | 
| 723 | 0 |  |  |  |  |  | continue; | 
| 724 |  |  |  |  |  |  |  | 
| 725 | 8 | 50 |  |  |  |  | if (b->exists != NULL) | 
| 726 | 8 |  |  |  |  |  | found = (bool)b->exists(b, id); | 
| 727 |  |  |  |  |  |  | } | 
| 728 |  |  |  |  |  |  |  | 
| 729 | 4 |  |  |  |  |  | return (int)found; | 
| 730 |  |  |  |  |  |  | } | 
| 731 |  |  |  |  |  |  |  | 
| 732 | 451 |  |  |  |  |  | static int odb_freshen_1( | 
| 733 |  |  |  |  |  |  | git_odb *db, | 
| 734 |  |  |  |  |  |  | const git_oid *id, | 
| 735 |  |  |  |  |  |  | bool only_refreshed) | 
| 736 |  |  |  |  |  |  | { | 
| 737 |  |  |  |  |  |  | size_t i; | 
| 738 | 451 |  |  |  |  |  | bool found = false; | 
| 739 |  |  |  |  |  |  |  | 
| 740 | 1363 | 100 |  |  |  |  | for (i = 0; i < db->backends.length && !found; ++i) { | 
|  |  | 100 |  |  |  |  |  | 
| 741 | 912 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 742 | 912 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 743 |  |  |  |  |  |  |  | 
| 744 | 912 | 100 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 100 |  |  |  |  |  | 
| 745 | 169 |  |  |  |  |  | continue; | 
| 746 |  |  |  |  |  |  |  | 
| 747 | 743 | 100 |  |  |  |  | if (b->freshen != NULL) | 
| 748 | 735 |  |  |  |  |  | found = !b->freshen(b, id); | 
| 749 | 8 | 50 |  |  |  |  | else if (b->exists != NULL) | 
| 750 | 8 |  |  |  |  |  | found = b->exists(b, id); | 
| 751 |  |  |  |  |  |  | } | 
| 752 |  |  |  |  |  |  |  | 
| 753 | 451 |  |  |  |  |  | return (int)found; | 
| 754 |  |  |  |  |  |  | } | 
| 755 |  |  |  |  |  |  |  | 
| 756 | 288 |  |  |  |  |  | int git_odb__freshen(git_odb *db, const git_oid *id) | 
| 757 |  |  |  |  |  |  | { | 
| 758 | 288 | 50 |  |  |  |  | assert(db && id); | 
|  |  | 50 |  |  |  |  |  | 
| 759 |  |  |  |  |  |  |  | 
| 760 | 288 | 100 |  |  |  |  | if (odb_freshen_1(db, id, false)) | 
| 761 | 125 |  |  |  |  |  | return 1; | 
| 762 |  |  |  |  |  |  |  | 
| 763 | 163 | 50 |  |  |  |  | if (!git_odb_refresh(db)) | 
| 764 | 163 |  |  |  |  |  | return odb_freshen_1(db, id, true); | 
| 765 |  |  |  |  |  |  |  | 
| 766 |  |  |  |  |  |  | /* Failed to refresh, hence not found */ | 
| 767 | 0 |  |  |  |  |  | return 0; | 
| 768 |  |  |  |  |  |  | } | 
| 769 |  |  |  |  |  |  |  | 
| 770 | 4 |  |  |  |  |  | int git_odb_exists(git_odb *db, const git_oid *id) | 
| 771 |  |  |  |  |  |  | { | 
| 772 |  |  |  |  |  |  | git_odb_object *object; | 
| 773 |  |  |  |  |  |  |  | 
| 774 | 4 | 50 |  |  |  |  | assert(db && id); | 
|  |  | 50 |  |  |  |  |  | 
| 775 |  |  |  |  |  |  |  | 
| 776 | 4 | 50 |  |  |  |  | if (git_oid_is_zero(id)) | 
| 777 | 0 |  |  |  |  |  | return 0; | 
| 778 |  |  |  |  |  |  |  | 
| 779 | 4 | 50 |  |  |  |  | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | 
| 780 | 0 |  |  |  |  |  | git_odb_object_free(object); | 
| 781 | 0 |  |  |  |  |  | return 1; | 
| 782 |  |  |  |  |  |  | } | 
| 783 |  |  |  |  |  |  |  | 
| 784 | 4 | 50 |  |  |  |  | if (odb_exists_1(db, id, false)) | 
| 785 | 4 |  |  |  |  |  | return 1; | 
| 786 |  |  |  |  |  |  |  | 
| 787 | 0 | 0 |  |  |  |  | if (!git_odb_refresh(db)) | 
| 788 | 0 |  |  |  |  |  | return odb_exists_1(db, id, true); | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | /* Failed to refresh, hence not found */ | 
| 791 | 0 |  |  |  |  |  | return 0; | 
| 792 |  |  |  |  |  |  | } | 
| 793 |  |  |  |  |  |  |  | 
| 794 | 0 |  |  |  |  |  | static int odb_exists_prefix_1(git_oid *out, git_odb *db, | 
| 795 |  |  |  |  |  |  | const git_oid *key, size_t len, bool only_refreshed) | 
| 796 |  |  |  |  |  |  | { | 
| 797 |  |  |  |  |  |  | size_t i; | 
| 798 | 0 |  |  |  |  |  | int error = GIT_ENOTFOUND, num_found = 0; | 
| 799 | 0 |  |  |  |  |  | git_oid last_found = {{0}}, found; | 
| 800 |  |  |  |  |  |  |  | 
| 801 | 0 | 0 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 802 | 0 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 803 | 0 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 804 |  |  |  |  |  |  |  | 
| 805 | 0 | 0 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 0 |  |  |  |  |  | 
| 806 | 0 |  |  |  |  |  | continue; | 
| 807 |  |  |  |  |  |  |  | 
| 808 | 0 | 0 |  |  |  |  | if (!b->exists_prefix) | 
| 809 | 0 |  |  |  |  |  | continue; | 
| 810 |  |  |  |  |  |  |  | 
| 811 | 0 |  |  |  |  |  | error = b->exists_prefix(&found, b, key, len); | 
| 812 | 0 | 0 |  |  |  |  | if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) | 
|  |  | 0 |  |  |  |  |  | 
| 813 | 0 |  |  |  |  |  | continue; | 
| 814 | 0 | 0 |  |  |  |  | if (error) | 
| 815 | 0 |  |  |  |  |  | return error; | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | /* make sure found item doesn't introduce ambiguity */ | 
| 818 | 0 | 0 |  |  |  |  | if (num_found) { | 
| 819 | 0 | 0 |  |  |  |  | if (git_oid__cmp(&last_found, &found)) | 
| 820 | 0 |  |  |  |  |  | return git_odb__error_ambiguous("multiple matches for prefix"); | 
| 821 |  |  |  |  |  |  | } else { | 
| 822 | 0 |  |  |  |  |  | git_oid_cpy(&last_found, &found); | 
| 823 | 0 |  |  |  |  |  | num_found++; | 
| 824 |  |  |  |  |  |  | } | 
| 825 |  |  |  |  |  |  | } | 
| 826 |  |  |  |  |  |  |  | 
| 827 | 0 | 0 |  |  |  |  | if (!num_found) | 
| 828 | 0 |  |  |  |  |  | return GIT_ENOTFOUND; | 
| 829 |  |  |  |  |  |  |  | 
| 830 | 0 | 0 |  |  |  |  | if (out) | 
| 831 | 0 |  |  |  |  |  | git_oid_cpy(out, &last_found); | 
| 832 |  |  |  |  |  |  |  | 
| 833 | 0 |  |  |  |  |  | return 0; | 
| 834 |  |  |  |  |  |  | } | 
| 835 |  |  |  |  |  |  |  | 
| 836 | 0 |  |  |  |  |  | int git_odb_exists_prefix( | 
| 837 |  |  |  |  |  |  | git_oid *out, git_odb *db, const git_oid *short_id, size_t len) | 
| 838 |  |  |  |  |  |  | { | 
| 839 |  |  |  |  |  |  | int error; | 
| 840 | 0 |  |  |  |  |  | git_oid key = {{0}}; | 
| 841 |  |  |  |  |  |  |  | 
| 842 | 0 | 0 |  |  |  |  | assert(db && short_id); | 
|  |  | 0 |  |  |  |  |  | 
| 843 |  |  |  |  |  |  |  | 
| 844 | 0 | 0 |  |  |  |  | if (len < GIT_OID_MINPREFIXLEN) | 
| 845 | 0 |  |  |  |  |  | return git_odb__error_ambiguous("prefix length too short"); | 
| 846 |  |  |  |  |  |  |  | 
| 847 | 0 | 0 |  |  |  |  | if (len >= GIT_OID_HEXSZ) { | 
| 848 | 0 | 0 |  |  |  |  | if (git_odb_exists(db, short_id)) { | 
| 849 | 0 | 0 |  |  |  |  | if (out) | 
| 850 | 0 |  |  |  |  |  | git_oid_cpy(out, short_id); | 
| 851 | 0 |  |  |  |  |  | return 0; | 
| 852 |  |  |  |  |  |  | } else { | 
| 853 | 0 |  |  |  |  |  | return git_odb__error_notfound( | 
| 854 |  |  |  |  |  |  | "no match for id prefix", short_id, len); | 
| 855 |  |  |  |  |  |  | } | 
| 856 |  |  |  |  |  |  | } | 
| 857 |  |  |  |  |  |  |  | 
| 858 | 0 |  |  |  |  |  | git_oid__cpy_prefix(&key, short_id, len); | 
| 859 |  |  |  |  |  |  |  | 
| 860 | 0 |  |  |  |  |  | error = odb_exists_prefix_1(out, db, &key, len, false); | 
| 861 |  |  |  |  |  |  |  | 
| 862 | 0 | 0 |  |  |  |  | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | 
|  |  | 0 |  |  |  |  |  | 
| 863 | 0 |  |  |  |  |  | error = odb_exists_prefix_1(out, db, &key, len, true); | 
| 864 |  |  |  |  |  |  |  | 
| 865 | 0 | 0 |  |  |  |  | if (error == GIT_ENOTFOUND) | 
| 866 | 0 |  |  |  |  |  | return git_odb__error_notfound("no match for id prefix", &key, len); | 
| 867 |  |  |  |  |  |  |  | 
| 868 | 0 |  |  |  |  |  | return error; | 
| 869 |  |  |  |  |  |  | } | 
| 870 |  |  |  |  |  |  |  | 
| 871 | 0 |  |  |  |  |  | int git_odb_expand_ids( | 
| 872 |  |  |  |  |  |  | git_odb *db, | 
| 873 |  |  |  |  |  |  | git_odb_expand_id *ids, | 
| 874 |  |  |  |  |  |  | size_t count) | 
| 875 |  |  |  |  |  |  | { | 
| 876 |  |  |  |  |  |  | size_t i; | 
| 877 |  |  |  |  |  |  |  | 
| 878 | 0 | 0 |  |  |  |  | assert(db && ids); | 
|  |  | 0 |  |  |  |  |  | 
| 879 |  |  |  |  |  |  |  | 
| 880 | 0 | 0 |  |  |  |  | for (i = 0; i < count; i++) { | 
| 881 | 0 |  |  |  |  |  | git_odb_expand_id *query = &ids[i]; | 
| 882 | 0 |  |  |  |  |  | int error = GIT_EAMBIGUOUS; | 
| 883 |  |  |  |  |  |  |  | 
| 884 | 0 | 0 |  |  |  |  | if (!query->type) | 
| 885 | 0 |  |  |  |  |  | query->type = GIT_OBJECT_ANY; | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | /* if we have a short OID, expand it first */ | 
| 888 | 0 | 0 |  |  |  |  | if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) { | 
|  |  | 0 |  |  |  |  |  | 
| 889 |  |  |  |  |  |  | git_oid actual_id; | 
| 890 |  |  |  |  |  |  |  | 
| 891 | 0 |  |  |  |  |  | error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false); | 
| 892 | 0 | 0 |  |  |  |  | if (!error) { | 
| 893 | 0 |  |  |  |  |  | git_oid_cpy(&query->id, &actual_id); | 
| 894 | 0 |  |  |  |  |  | query->length = GIT_OID_HEXSZ; | 
| 895 |  |  |  |  |  |  | } | 
| 896 |  |  |  |  |  |  | } | 
| 897 |  |  |  |  |  |  |  | 
| 898 |  |  |  |  |  |  | /* | 
| 899 |  |  |  |  |  |  | * now we ought to have a 40-char OID, either because we've expanded it | 
| 900 |  |  |  |  |  |  | * or because the user passed a full OID. Ensure its type is right. | 
| 901 |  |  |  |  |  |  | */ | 
| 902 | 0 | 0 |  |  |  |  | if (query->length >= GIT_OID_HEXSZ) { | 
| 903 |  |  |  |  |  |  | git_object_t actual_type; | 
| 904 |  |  |  |  |  |  |  | 
| 905 | 0 |  |  |  |  |  | error = odb_otype_fast(&actual_type, db, &query->id); | 
| 906 | 0 | 0 |  |  |  |  | if (!error) { | 
| 907 | 0 | 0 |  |  |  |  | if (query->type != GIT_OBJECT_ANY && query->type != actual_type) | 
|  |  | 0 |  |  |  |  |  | 
| 908 | 0 |  |  |  |  |  | error = GIT_ENOTFOUND; | 
| 909 |  |  |  |  |  |  | else | 
| 910 | 0 |  |  |  |  |  | query->type = actual_type; | 
| 911 |  |  |  |  |  |  | } | 
| 912 |  |  |  |  |  |  | } | 
| 913 |  |  |  |  |  |  |  | 
| 914 | 0 |  |  |  |  |  | switch (error) { | 
| 915 |  |  |  |  |  |  | /* no errors, so we've successfully expanded the OID */ | 
| 916 |  |  |  |  |  |  | case 0: | 
| 917 | 0 |  |  |  |  |  | continue; | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | /* the object is missing or ambiguous */ | 
| 920 |  |  |  |  |  |  | case GIT_ENOTFOUND: | 
| 921 |  |  |  |  |  |  | case GIT_EAMBIGUOUS: | 
| 922 | 0 |  |  |  |  |  | memset(&query->id, 0, sizeof(git_oid)); | 
| 923 | 0 |  |  |  |  |  | query->length = 0; | 
| 924 | 0 |  |  |  |  |  | query->type = 0; | 
| 925 | 0 |  |  |  |  |  | break; | 
| 926 |  |  |  |  |  |  |  | 
| 927 |  |  |  |  |  |  | /* something went very wrong with the ODB; bail hard */ | 
| 928 |  |  |  |  |  |  | default: | 
| 929 | 0 |  |  |  |  |  | return error; | 
| 930 |  |  |  |  |  |  | } | 
| 931 |  |  |  |  |  |  | } | 
| 932 |  |  |  |  |  |  |  | 
| 933 | 0 |  |  |  |  |  | git_error_clear(); | 
| 934 | 0 |  |  |  |  |  | return 0; | 
| 935 |  |  |  |  |  |  | } | 
| 936 |  |  |  |  |  |  |  | 
| 937 | 382 |  |  |  |  |  | int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id) | 
| 938 |  |  |  |  |  |  | { | 
| 939 |  |  |  |  |  |  | int error; | 
| 940 |  |  |  |  |  |  | git_odb_object *object; | 
| 941 |  |  |  |  |  |  |  | 
| 942 | 382 |  |  |  |  |  | error = git_odb__read_header_or_object(&object, len_p, type_p, db, id); | 
| 943 |  |  |  |  |  |  |  | 
| 944 | 382 | 100 |  |  |  |  | if (object) | 
| 945 | 3 |  |  |  |  |  | git_odb_object_free(object); | 
| 946 |  |  |  |  |  |  |  | 
| 947 | 382 |  |  |  |  |  | return error; | 
| 948 |  |  |  |  |  |  | } | 
| 949 |  |  |  |  |  |  |  | 
| 950 | 396 |  |  |  |  |  | static int odb_read_header_1( | 
| 951 |  |  |  |  |  |  | size_t *len_p, git_object_t *type_p, git_odb *db, | 
| 952 |  |  |  |  |  |  | const git_oid *id, bool only_refreshed) | 
| 953 |  |  |  |  |  |  | { | 
| 954 |  |  |  |  |  |  | size_t i; | 
| 955 |  |  |  |  |  |  | git_object_t ht; | 
| 956 | 396 |  |  |  |  |  | bool passthrough = false; | 
| 957 |  |  |  |  |  |  | int error; | 
| 958 |  |  |  |  |  |  |  | 
| 959 | 396 | 50 |  |  |  |  | if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) { | 
|  |  | 50 |  |  |  |  |  | 
| 960 | 0 |  |  |  |  |  | *type_p = ht; | 
| 961 | 0 |  |  |  |  |  | *len_p = 0; | 
| 962 | 0 |  |  |  |  |  | return 0; | 
| 963 |  |  |  |  |  |  | } | 
| 964 |  |  |  |  |  |  |  | 
| 965 | 787 | 50 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 966 | 787 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 967 | 787 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 968 |  |  |  |  |  |  |  | 
| 969 | 787 | 50 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 0 |  |  |  |  |  | 
| 970 | 0 |  |  |  |  |  | continue; | 
| 971 |  |  |  |  |  |  |  | 
| 972 | 787 | 50 |  |  |  |  | if (!b->read_header) { | 
| 973 | 0 |  |  |  |  |  | passthrough = true; | 
| 974 | 0 |  |  |  |  |  | continue; | 
| 975 |  |  |  |  |  |  | } | 
| 976 |  |  |  |  |  |  |  | 
| 977 | 787 |  |  |  |  |  | error = b->read_header(len_p, type_p, b, id); | 
| 978 |  |  |  |  |  |  |  | 
| 979 | 787 |  |  |  |  |  | switch (error) { | 
| 980 |  |  |  |  |  |  | case GIT_PASSTHROUGH: | 
| 981 | 0 |  |  |  |  |  | passthrough = true; | 
| 982 | 0 |  |  |  |  |  | break; | 
| 983 |  |  |  |  |  |  | case GIT_ENOTFOUND: | 
| 984 | 391 |  |  |  |  |  | break; | 
| 985 |  |  |  |  |  |  | default: | 
| 986 | 396 |  |  |  |  |  | return error; | 
| 987 |  |  |  |  |  |  | } | 
| 988 |  |  |  |  |  |  | } | 
| 989 |  |  |  |  |  |  |  | 
| 990 | 0 | 0 |  |  |  |  | return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND; | 
| 991 |  |  |  |  |  |  | } | 
| 992 |  |  |  |  |  |  |  | 
| 993 | 399 |  |  |  |  |  | int git_odb__read_header_or_object( | 
| 994 |  |  |  |  |  |  | git_odb_object **out, size_t *len_p, git_object_t *type_p, | 
| 995 |  |  |  |  |  |  | git_odb *db, const git_oid *id) | 
| 996 |  |  |  |  |  |  | { | 
| 997 | 399 |  |  |  |  |  | int error = GIT_ENOTFOUND; | 
| 998 |  |  |  |  |  |  | git_odb_object *object; | 
| 999 |  |  |  |  |  |  |  | 
| 1000 | 399 | 50 |  |  |  |  | assert(db && id && out && len_p && type_p); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1001 |  |  |  |  |  |  |  | 
| 1002 | 399 |  |  |  |  |  | *out = NULL; | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 | 399 | 50 |  |  |  |  | if (git_oid_is_zero(id)) | 
| 1005 | 0 |  |  |  |  |  | return error_null_oid(GIT_ENOTFOUND, "cannot read object"); | 
| 1006 |  |  |  |  |  |  |  | 
| 1007 | 399 | 100 |  |  |  |  | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | 
| 1008 | 3 |  |  |  |  |  | *len_p = object->cached.size; | 
| 1009 | 3 |  |  |  |  |  | *type_p = object->cached.type; | 
| 1010 | 3 |  |  |  |  |  | *out = object; | 
| 1011 | 3 |  |  |  |  |  | return 0; | 
| 1012 |  |  |  |  |  |  | } | 
| 1013 |  |  |  |  |  |  |  | 
| 1014 | 396 |  |  |  |  |  | error = odb_read_header_1(len_p, type_p, db, id, false); | 
| 1015 |  |  |  |  |  |  |  | 
| 1016 | 396 | 50 |  |  |  |  | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | 
|  |  | 0 |  |  |  |  |  | 
| 1017 | 0 |  |  |  |  |  | error = odb_read_header_1(len_p, type_p, db, id, true); | 
| 1018 |  |  |  |  |  |  |  | 
| 1019 | 396 | 50 |  |  |  |  | if (error == GIT_ENOTFOUND) | 
| 1020 | 0 |  |  |  |  |  | return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ); | 
| 1021 |  |  |  |  |  |  |  | 
| 1022 |  |  |  |  |  |  | /* we found the header; return early */ | 
| 1023 | 396 | 50 |  |  |  |  | if (!error) | 
| 1024 | 396 |  |  |  |  |  | return 0; | 
| 1025 |  |  |  |  |  |  |  | 
| 1026 | 0 | 0 |  |  |  |  | if (error == GIT_PASSTHROUGH) { | 
| 1027 |  |  |  |  |  |  | /* | 
| 1028 |  |  |  |  |  |  | * no backend has header-reading functionality | 
| 1029 |  |  |  |  |  |  | * so try using `git_odb_read` instead | 
| 1030 |  |  |  |  |  |  | */ | 
| 1031 | 0 |  |  |  |  |  | error = git_odb_read(&object, db, id); | 
| 1032 | 0 | 0 |  |  |  |  | if (!error) { | 
| 1033 | 0 |  |  |  |  |  | *len_p = object->cached.size; | 
| 1034 | 0 |  |  |  |  |  | *type_p = object->cached.type; | 
| 1035 | 0 |  |  |  |  |  | *out = object; | 
| 1036 |  |  |  |  |  |  | } | 
| 1037 |  |  |  |  |  |  | } | 
| 1038 |  |  |  |  |  |  |  | 
| 1039 | 399 |  |  |  |  |  | return error; | 
| 1040 |  |  |  |  |  |  | } | 
| 1041 |  |  |  |  |  |  |  | 
| 1042 | 652 |  |  |  |  |  | static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, | 
| 1043 |  |  |  |  |  |  | bool only_refreshed) | 
| 1044 |  |  |  |  |  |  | { | 
| 1045 |  |  |  |  |  |  | size_t i; | 
| 1046 |  |  |  |  |  |  | git_rawobj raw; | 
| 1047 |  |  |  |  |  |  | git_odb_object *object; | 
| 1048 |  |  |  |  |  |  | git_oid hashed; | 
| 1049 | 652 |  |  |  |  |  | bool found = false; | 
| 1050 | 652 |  |  |  |  |  | int error = 0; | 
| 1051 |  |  |  |  |  |  |  | 
| 1052 | 652 | 100 |  |  |  |  | if (!only_refreshed) { | 
| 1053 | 649 | 50 |  |  |  |  | if ((error = odb_read_hardcoded(&found, &raw, id)) < 0) | 
| 1054 | 0 |  |  |  |  |  | return error; | 
| 1055 |  |  |  |  |  |  | } | 
| 1056 |  |  |  |  |  |  |  | 
| 1057 | 1942 | 100 |  |  |  |  | for (i = 0; i < db->backends.length && !found; ++i) { | 
|  |  | 100 |  |  |  |  |  | 
| 1058 | 1290 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1059 | 1290 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1060 |  |  |  |  |  |  |  | 
| 1061 | 1290 | 100 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 100 |  |  |  |  |  | 
| 1062 | 3 |  |  |  |  |  | continue; | 
| 1063 |  |  |  |  |  |  |  | 
| 1064 | 1287 | 50 |  |  |  |  | if (b->read != NULL) { | 
| 1065 | 1287 |  |  |  |  |  | error = b->read(&raw.data, &raw.len, &raw.type, b, id); | 
| 1066 | 1287 | 50 |  |  |  |  | if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND) | 
|  |  | 100 |  |  |  |  |  | 
| 1067 | 642 |  |  |  |  |  | continue; | 
| 1068 |  |  |  |  |  |  |  | 
| 1069 | 645 | 50 |  |  |  |  | if (error < 0) | 
| 1070 | 0 |  |  |  |  |  | return error; | 
| 1071 |  |  |  |  |  |  |  | 
| 1072 | 645 |  |  |  |  |  | found = true; | 
| 1073 |  |  |  |  |  |  | } | 
| 1074 |  |  |  |  |  |  | } | 
| 1075 |  |  |  |  |  |  |  | 
| 1076 | 652 | 100 |  |  |  |  | if (!found) | 
| 1077 | 6 |  |  |  |  |  | return GIT_ENOTFOUND; | 
| 1078 |  |  |  |  |  |  |  | 
| 1079 | 646 | 50 |  |  |  |  | if (git_odb__strict_hash_verification) { | 
| 1080 | 646 | 50 |  |  |  |  | if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0) | 
| 1081 | 0 |  |  |  |  |  | goto out; | 
| 1082 |  |  |  |  |  |  |  | 
| 1083 | 646 | 50 |  |  |  |  | if (!git_oid_equal(id, &hashed)) { | 
| 1084 | 0 |  |  |  |  |  | error = git_odb__error_mismatch(id, &hashed); | 
| 1085 | 0 |  |  |  |  |  | goto out; | 
| 1086 |  |  |  |  |  |  | } | 
| 1087 |  |  |  |  |  |  | } | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 | 646 |  |  |  |  |  | git_error_clear(); | 
| 1090 | 646 | 50 |  |  |  |  | if ((object = odb_object__alloc(id, &raw)) == NULL) { | 
| 1091 | 0 |  |  |  |  |  | error = -1; | 
| 1092 | 0 |  |  |  |  |  | goto out; | 
| 1093 |  |  |  |  |  |  | } | 
| 1094 |  |  |  |  |  |  |  | 
| 1095 | 646 |  |  |  |  |  | *out = git_cache_store_raw(odb_cache(db), object); | 
| 1096 |  |  |  |  |  |  |  | 
| 1097 |  |  |  |  |  |  | out: | 
| 1098 | 646 | 50 |  |  |  |  | if (error) | 
| 1099 | 0 |  |  |  |  |  | git__free(raw.data); | 
| 1100 | 652 |  |  |  |  |  | return error; | 
| 1101 |  |  |  |  |  |  | } | 
| 1102 |  |  |  |  |  |  |  | 
| 1103 | 649 |  |  |  |  |  | int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) | 
| 1104 |  |  |  |  |  |  | { | 
| 1105 |  |  |  |  |  |  | int error; | 
| 1106 |  |  |  |  |  |  |  | 
| 1107 | 649 | 50 |  |  |  |  | assert(out && db && id); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1108 |  |  |  |  |  |  |  | 
| 1109 | 649 | 50 |  |  |  |  | if (git_oid_is_zero(id)) | 
| 1110 | 0 |  |  |  |  |  | return error_null_oid(GIT_ENOTFOUND, "cannot read object"); | 
| 1111 |  |  |  |  |  |  |  | 
| 1112 | 649 |  |  |  |  |  | *out = git_cache_get_raw(odb_cache(db), id); | 
| 1113 | 649 | 50 |  |  |  |  | if (*out != NULL) | 
| 1114 | 0 |  |  |  |  |  | return 0; | 
| 1115 |  |  |  |  |  |  |  | 
| 1116 | 649 |  |  |  |  |  | error = odb_read_1(out, db, id, false); | 
| 1117 |  |  |  |  |  |  |  | 
| 1118 | 649 | 100 |  |  |  |  | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | 
|  |  | 50 |  |  |  |  |  | 
| 1119 | 3 |  |  |  |  |  | error = odb_read_1(out, db, id, true); | 
| 1120 |  |  |  |  |  |  |  | 
| 1121 | 649 | 100 |  |  |  |  | if (error == GIT_ENOTFOUND) | 
| 1122 | 3 |  |  |  |  |  | return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ); | 
| 1123 |  |  |  |  |  |  |  | 
| 1124 | 646 |  |  |  |  |  | return error; | 
| 1125 |  |  |  |  |  |  | } | 
| 1126 |  |  |  |  |  |  |  | 
| 1127 | 0 |  |  |  |  |  | static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id) | 
| 1128 |  |  |  |  |  |  | { | 
| 1129 |  |  |  |  |  |  | git_odb_object *object; | 
| 1130 |  |  |  |  |  |  | size_t _unused; | 
| 1131 |  |  |  |  |  |  | int error; | 
| 1132 |  |  |  |  |  |  |  | 
| 1133 | 0 | 0 |  |  |  |  | if (git_oid_is_zero(id)) | 
| 1134 | 0 |  |  |  |  |  | return error_null_oid(GIT_ENOTFOUND, "cannot get object type"); | 
| 1135 |  |  |  |  |  |  |  | 
| 1136 | 0 | 0 |  |  |  |  | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | 
| 1137 | 0 |  |  |  |  |  | *type_p = object->cached.type; | 
| 1138 | 0 |  |  |  |  |  | git_odb_object_free(object); | 
| 1139 | 0 |  |  |  |  |  | return 0; | 
| 1140 |  |  |  |  |  |  | } | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 | 0 |  |  |  |  |  | error = odb_read_header_1(&_unused, type_p, db, id, false); | 
| 1143 |  |  |  |  |  |  |  | 
| 1144 | 0 | 0 |  |  |  |  | if (error == GIT_PASSTHROUGH) { | 
| 1145 | 0 |  |  |  |  |  | error = odb_read_1(&object, db, id, false); | 
| 1146 | 0 | 0 |  |  |  |  | if (!error) | 
| 1147 | 0 |  |  |  |  |  | *type_p = object->cached.type; | 
| 1148 | 0 |  |  |  |  |  | git_odb_object_free(object); | 
| 1149 |  |  |  |  |  |  | } | 
| 1150 |  |  |  |  |  |  |  | 
| 1151 | 0 |  |  |  |  |  | return error; | 
| 1152 |  |  |  |  |  |  | } | 
| 1153 |  |  |  |  |  |  |  | 
| 1154 | 146 |  |  |  |  |  | static int read_prefix_1(git_odb_object **out, git_odb *db, | 
| 1155 |  |  |  |  |  |  | const git_oid *key, size_t len, bool only_refreshed) | 
| 1156 |  |  |  |  |  |  | { | 
| 1157 |  |  |  |  |  |  | size_t i; | 
| 1158 | 146 |  |  |  |  |  | int error = 0; | 
| 1159 | 146 |  |  |  |  |  | git_oid found_full_oid = {{0}}; | 
| 1160 | 146 |  |  |  |  |  | git_rawobj raw = {0}; | 
| 1161 | 146 |  |  |  |  |  | void *data = NULL; | 
| 1162 | 146 |  |  |  |  |  | bool found = false; | 
| 1163 |  |  |  |  |  |  | git_odb_object *object; | 
| 1164 |  |  |  |  |  |  |  | 
| 1165 | 438 | 100 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 1166 | 292 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1167 | 292 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1168 |  |  |  |  |  |  |  | 
| 1169 | 292 | 100 |  |  |  |  | if (only_refreshed && !b->refresh) | 
|  |  | 100 |  |  |  |  |  | 
| 1170 | 8 |  |  |  |  |  | continue; | 
| 1171 |  |  |  |  |  |  |  | 
| 1172 | 284 | 50 |  |  |  |  | if (b->read_prefix != NULL) { | 
| 1173 |  |  |  |  |  |  | git_oid full_oid; | 
| 1174 | 284 |  |  |  |  |  | error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len); | 
| 1175 |  |  |  |  |  |  |  | 
| 1176 | 284 | 100 |  |  |  |  | if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) { | 
|  |  | 50 |  |  |  |  |  | 
| 1177 | 154 |  |  |  |  |  | error = 0; | 
| 1178 | 154 |  |  |  |  |  | continue; | 
| 1179 |  |  |  |  |  |  | } | 
| 1180 |  |  |  |  |  |  |  | 
| 1181 | 130 | 50 |  |  |  |  | if (error) | 
| 1182 | 0 |  |  |  |  |  | goto out; | 
| 1183 |  |  |  |  |  |  |  | 
| 1184 | 130 |  |  |  |  |  | git__free(data); | 
| 1185 | 130 |  |  |  |  |  | data = raw.data; | 
| 1186 |  |  |  |  |  |  |  | 
| 1187 | 130 | 50 |  |  |  |  | if (found && git_oid__cmp(&full_oid, &found_full_oid)) { | 
|  |  | 0 |  |  |  |  |  | 
| 1188 | 0 |  |  |  |  |  | git_buf buf = GIT_BUF_INIT; | 
| 1189 |  |  |  |  |  |  |  | 
| 1190 | 0 |  |  |  |  |  | git_buf_printf(&buf, "multiple matches for prefix: %s", | 
| 1191 |  |  |  |  |  |  | git_oid_tostr_s(&full_oid)); | 
| 1192 | 0 |  |  |  |  |  | git_buf_printf(&buf, " %s", | 
| 1193 |  |  |  |  |  |  | git_oid_tostr_s(&found_full_oid)); | 
| 1194 |  |  |  |  |  |  |  | 
| 1195 | 0 |  |  |  |  |  | error = git_odb__error_ambiguous(buf.ptr); | 
| 1196 | 0 |  |  |  |  |  | git_buf_dispose(&buf); | 
| 1197 | 0 |  |  |  |  |  | goto out; | 
| 1198 |  |  |  |  |  |  | } | 
| 1199 |  |  |  |  |  |  |  | 
| 1200 | 130 |  |  |  |  |  | found_full_oid = full_oid; | 
| 1201 | 130 |  |  |  |  |  | found = true; | 
| 1202 |  |  |  |  |  |  | } | 
| 1203 |  |  |  |  |  |  | } | 
| 1204 |  |  |  |  |  |  |  | 
| 1205 | 146 | 100 |  |  |  |  | if (!found) | 
| 1206 | 16 |  |  |  |  |  | return GIT_ENOTFOUND; | 
| 1207 |  |  |  |  |  |  |  | 
| 1208 | 130 | 50 |  |  |  |  | if (git_odb__strict_hash_verification) { | 
| 1209 |  |  |  |  |  |  | git_oid hash; | 
| 1210 |  |  |  |  |  |  |  | 
| 1211 | 130 | 50 |  |  |  |  | if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0) | 
| 1212 | 0 |  |  |  |  |  | goto out; | 
| 1213 |  |  |  |  |  |  |  | 
| 1214 | 130 | 50 |  |  |  |  | if (!git_oid_equal(&found_full_oid, &hash)) { | 
| 1215 | 130 |  |  |  |  |  | error = git_odb__error_mismatch(&found_full_oid, &hash); | 
| 1216 | 0 |  |  |  |  |  | goto out; | 
| 1217 |  |  |  |  |  |  | } | 
| 1218 |  |  |  |  |  |  | } | 
| 1219 |  |  |  |  |  |  |  | 
| 1220 | 130 | 50 |  |  |  |  | if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) { | 
| 1221 | 0 |  |  |  |  |  | error = -1; | 
| 1222 | 0 |  |  |  |  |  | goto out; | 
| 1223 |  |  |  |  |  |  | } | 
| 1224 |  |  |  |  |  |  |  | 
| 1225 | 130 |  |  |  |  |  | *out = git_cache_store_raw(odb_cache(db), object); | 
| 1226 |  |  |  |  |  |  |  | 
| 1227 |  |  |  |  |  |  | out: | 
| 1228 | 130 | 50 |  |  |  |  | if (error) | 
| 1229 | 0 |  |  |  |  |  | git__free(raw.data); | 
| 1230 |  |  |  |  |  |  |  | 
| 1231 | 146 |  |  |  |  |  | return error; | 
| 1232 |  |  |  |  |  |  | } | 
| 1233 |  |  |  |  |  |  |  | 
| 1234 | 138 |  |  |  |  |  | int git_odb_read_prefix( | 
| 1235 |  |  |  |  |  |  | git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len) | 
| 1236 |  |  |  |  |  |  | { | 
| 1237 | 138 |  |  |  |  |  | git_oid key = {{0}}; | 
| 1238 |  |  |  |  |  |  | int error; | 
| 1239 |  |  |  |  |  |  |  | 
| 1240 | 138 | 50 |  |  |  |  | assert(out && db); | 
|  |  | 50 |  |  |  |  |  | 
| 1241 |  |  |  |  |  |  |  | 
| 1242 | 138 | 50 |  |  |  |  | if (len < GIT_OID_MINPREFIXLEN) | 
| 1243 | 0 |  |  |  |  |  | return git_odb__error_ambiguous("prefix length too short"); | 
| 1244 |  |  |  |  |  |  |  | 
| 1245 | 138 | 50 |  |  |  |  | if (len > GIT_OID_HEXSZ) | 
| 1246 | 0 |  |  |  |  |  | len = GIT_OID_HEXSZ; | 
| 1247 |  |  |  |  |  |  |  | 
| 1248 | 138 | 100 |  |  |  |  | if (len == GIT_OID_HEXSZ) { | 
| 1249 | 122 |  |  |  |  |  | *out = git_cache_get_raw(odb_cache(db), short_id); | 
| 1250 | 122 | 50 |  |  |  |  | if (*out != NULL) | 
| 1251 | 0 |  |  |  |  |  | return 0; | 
| 1252 |  |  |  |  |  |  | } | 
| 1253 |  |  |  |  |  |  |  | 
| 1254 | 138 |  |  |  |  |  | git_oid__cpy_prefix(&key, short_id, len); | 
| 1255 |  |  |  |  |  |  |  | 
| 1256 | 138 |  |  |  |  |  | error = read_prefix_1(out, db, &key, len, false); | 
| 1257 |  |  |  |  |  |  |  | 
| 1258 | 138 | 100 |  |  |  |  | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | 
|  |  | 50 |  |  |  |  |  | 
| 1259 | 8 |  |  |  |  |  | error = read_prefix_1(out, db, &key, len, true); | 
| 1260 |  |  |  |  |  |  |  | 
| 1261 | 138 | 100 |  |  |  |  | if (error == GIT_ENOTFOUND) | 
| 1262 | 8 |  |  |  |  |  | return git_odb__error_notfound("no match for prefix", &key, len); | 
| 1263 |  |  |  |  |  |  |  | 
| 1264 | 138 |  |  |  |  |  | return error; | 
| 1265 |  |  |  |  |  |  | } | 
| 1266 |  |  |  |  |  |  |  | 
| 1267 | 1 |  |  |  |  |  | int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload) | 
| 1268 |  |  |  |  |  |  | { | 
| 1269 |  |  |  |  |  |  | unsigned int i; | 
| 1270 |  |  |  |  |  |  | backend_internal *internal; | 
| 1271 |  |  |  |  |  |  |  | 
| 1272 | 3 | 100 |  |  |  |  | git_vector_foreach(&db->backends, i, internal) { | 
| 1273 | 2 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1274 | 2 |  |  |  |  |  | int error = b->foreach(b, cb, payload); | 
| 1275 | 2 | 50 |  |  |  |  | if (error != 0) | 
| 1276 | 0 |  |  |  |  |  | return error; | 
| 1277 |  |  |  |  |  |  | } | 
| 1278 |  |  |  |  |  |  |  | 
| 1279 | 1 |  |  |  |  |  | return 0; | 
| 1280 |  |  |  |  |  |  | } | 
| 1281 |  |  |  |  |  |  |  | 
| 1282 | 171 |  |  |  |  |  | int git_odb_write( | 
| 1283 |  |  |  |  |  |  | git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type) | 
| 1284 |  |  |  |  |  |  | { | 
| 1285 |  |  |  |  |  |  | size_t i; | 
| 1286 |  |  |  |  |  |  | int error; | 
| 1287 |  |  |  |  |  |  | git_odb_stream *stream; | 
| 1288 |  |  |  |  |  |  |  | 
| 1289 | 171 | 50 |  |  |  |  | assert(oid && db); | 
|  |  | 50 |  |  |  |  |  | 
| 1290 |  |  |  |  |  |  |  | 
| 1291 | 171 | 50 |  |  |  |  | if ((error = git_odb_hash(oid, data, len, type)) < 0) | 
| 1292 | 0 |  |  |  |  |  | return error; | 
| 1293 |  |  |  |  |  |  |  | 
| 1294 | 171 | 50 |  |  |  |  | if (git_oid_is_zero(oid)) | 
| 1295 | 0 |  |  |  |  |  | return error_null_oid(GIT_EINVALID, "cannot write object"); | 
| 1296 |  |  |  |  |  |  |  | 
| 1297 | 171 | 100 |  |  |  |  | if (git_odb__freshen(db, oid)) | 
| 1298 | 51 |  |  |  |  |  | return 0; | 
| 1299 |  |  |  |  |  |  |  | 
| 1300 | 354 | 100 |  |  |  |  | for (i = 0, error = GIT_ERROR; i < db->backends.length && error < 0; ++i) { | 
|  |  | 100 |  |  |  |  |  | 
| 1301 | 234 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1302 | 234 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1303 |  |  |  |  |  |  |  | 
| 1304 |  |  |  |  |  |  | /* we don't write in alternates! */ | 
| 1305 | 234 | 50 |  |  |  |  | if (internal->is_alternate) | 
| 1306 | 0 |  |  |  |  |  | continue; | 
| 1307 |  |  |  |  |  |  |  | 
| 1308 | 234 | 100 |  |  |  |  | if (b->write != NULL) | 
| 1309 | 120 |  |  |  |  |  | error = b->write(b, oid, data, len, type); | 
| 1310 |  |  |  |  |  |  | } | 
| 1311 |  |  |  |  |  |  |  | 
| 1312 | 120 | 50 |  |  |  |  | if (!error || error == GIT_PASSTHROUGH) | 
|  |  | 0 |  |  |  |  |  | 
| 1313 | 120 |  |  |  |  |  | return 0; | 
| 1314 |  |  |  |  |  |  |  | 
| 1315 |  |  |  |  |  |  | /* if no backends were able to write the object directly, we try a | 
| 1316 |  |  |  |  |  |  | * streaming write to the backends; just write the whole object into the | 
| 1317 |  |  |  |  |  |  | * stream in one push | 
| 1318 |  |  |  |  |  |  | */ | 
| 1319 | 0 | 0 |  |  |  |  | if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0) | 
| 1320 | 0 |  |  |  |  |  | return error; | 
| 1321 |  |  |  |  |  |  |  | 
| 1322 | 0 |  |  |  |  |  | stream->write(stream, data, len); | 
| 1323 | 0 |  |  |  |  |  | error = stream->finalize_write(stream, oid); | 
| 1324 | 0 |  |  |  |  |  | git_odb_stream_free(stream); | 
| 1325 |  |  |  |  |  |  |  | 
| 1326 | 171 |  |  |  |  |  | return error; | 
| 1327 |  |  |  |  |  |  | } | 
| 1328 |  |  |  |  |  |  |  | 
| 1329 | 63 |  |  |  |  |  | static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type) | 
| 1330 |  |  |  |  |  |  | { | 
| 1331 |  |  |  |  |  |  | char header[64]; | 
| 1332 |  |  |  |  |  |  | size_t hdrlen; | 
| 1333 |  |  |  |  |  |  | int error; | 
| 1334 |  |  |  |  |  |  |  | 
| 1335 | 63 | 50 |  |  |  |  | if ((error = git_odb__format_object_header(&hdrlen, | 
| 1336 |  |  |  |  |  |  | header, sizeof(header), size, type)) < 0) | 
| 1337 | 0 |  |  |  |  |  | return error; | 
| 1338 |  |  |  |  |  |  |  | 
| 1339 | 63 |  |  |  |  |  | return git_hash_update(ctx, header, hdrlen); | 
| 1340 |  |  |  |  |  |  | } | 
| 1341 |  |  |  |  |  |  |  | 
| 1342 | 63 |  |  |  |  |  | int git_odb_open_wstream( | 
| 1343 |  |  |  |  |  |  | git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type) | 
| 1344 |  |  |  |  |  |  | { | 
| 1345 | 63 |  |  |  |  |  | size_t i, writes = 0; | 
| 1346 | 63 |  |  |  |  |  | int error = GIT_ERROR; | 
| 1347 | 63 |  |  |  |  |  | git_hash_ctx *ctx = NULL; | 
| 1348 |  |  |  |  |  |  |  | 
| 1349 | 63 | 50 |  |  |  |  | assert(stream && db); | 
|  |  | 50 |  |  |  |  |  | 
| 1350 |  |  |  |  |  |  |  | 
| 1351 | 189 | 100 |  |  |  |  | for (i = 0; i < db->backends.length && error < 0; ++i) { | 
|  |  | 50 |  |  |  |  |  | 
| 1352 | 126 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1353 | 126 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1354 |  |  |  |  |  |  |  | 
| 1355 |  |  |  |  |  |  | /* we don't write in alternates! */ | 
| 1356 | 126 | 50 |  |  |  |  | if (internal->is_alternate) | 
| 1357 | 0 |  |  |  |  |  | continue; | 
| 1358 |  |  |  |  |  |  |  | 
| 1359 | 126 | 100 |  |  |  |  | if (b->writestream != NULL) { | 
| 1360 | 63 |  |  |  |  |  | ++writes; | 
| 1361 | 63 |  |  |  |  |  | error = b->writestream(stream, b, size, type); | 
| 1362 | 63 | 50 |  |  |  |  | } else if (b->write != NULL) { | 
| 1363 | 0 |  |  |  |  |  | ++writes; | 
| 1364 | 0 |  |  |  |  |  | error = init_fake_wstream(stream, b, size, type); | 
| 1365 |  |  |  |  |  |  | } | 
| 1366 |  |  |  |  |  |  | } | 
| 1367 |  |  |  |  |  |  |  | 
| 1368 | 63 | 50 |  |  |  |  | if (error < 0) { | 
| 1369 | 0 | 0 |  |  |  |  | if (error == GIT_PASSTHROUGH) | 
| 1370 | 0 |  |  |  |  |  | error = 0; | 
| 1371 | 0 | 0 |  |  |  |  | else if (!writes) | 
| 1372 | 0 |  |  |  |  |  | error = git_odb__error_unsupported_in_backend("write object"); | 
| 1373 |  |  |  |  |  |  |  | 
| 1374 | 0 |  |  |  |  |  | goto done; | 
| 1375 |  |  |  |  |  |  | } | 
| 1376 |  |  |  |  |  |  |  | 
| 1377 | 63 |  |  |  |  |  | ctx = git__malloc(sizeof(git_hash_ctx)); | 
| 1378 | 63 | 50 |  |  |  |  | GIT_ERROR_CHECK_ALLOC(ctx); | 
| 1379 |  |  |  |  |  |  |  | 
| 1380 | 63 | 50 |  |  |  |  | if ((error = git_hash_ctx_init(ctx)) < 0 || | 
|  |  | 50 |  |  |  |  |  | 
| 1381 |  |  |  |  |  |  | (error = hash_header(ctx, size, type)) < 0) | 
| 1382 |  |  |  |  |  |  | goto done; | 
| 1383 |  |  |  |  |  |  |  | 
| 1384 | 63 |  |  |  |  |  | (*stream)->hash_ctx = ctx; | 
| 1385 | 63 |  |  |  |  |  | (*stream)->declared_size = size; | 
| 1386 | 63 |  |  |  |  |  | (*stream)->received_bytes = 0; | 
| 1387 |  |  |  |  |  |  |  | 
| 1388 |  |  |  |  |  |  | done: | 
| 1389 | 63 | 50 |  |  |  |  | if (error) | 
| 1390 | 0 |  |  |  |  |  | git__free(ctx); | 
| 1391 | 63 |  |  |  |  |  | return error; | 
| 1392 |  |  |  |  |  |  | } | 
| 1393 |  |  |  |  |  |  |  | 
| 1394 | 0 |  |  |  |  |  | static int git_odb_stream__invalid_length( | 
| 1395 |  |  |  |  |  |  | const git_odb_stream *stream, | 
| 1396 |  |  |  |  |  |  | const char *action) | 
| 1397 |  |  |  |  |  |  | { | 
| 1398 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, | 
| 1399 |  |  |  |  |  |  | "cannot %s - " | 
| 1400 |  |  |  |  |  |  | "Invalid length. %"PRId64" was expected. The " | 
| 1401 |  |  |  |  |  |  | "total size of the received chunks amounts to %"PRId64".", | 
| 1402 |  |  |  |  |  |  | action, stream->declared_size, stream->received_bytes); | 
| 1403 |  |  |  |  |  |  |  | 
| 1404 | 0 |  |  |  |  |  | return -1; | 
| 1405 |  |  |  |  |  |  | } | 
| 1406 |  |  |  |  |  |  |  | 
| 1407 | 62 |  |  |  |  |  | int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len) | 
| 1408 |  |  |  |  |  |  | { | 
| 1409 | 62 |  |  |  |  |  | git_hash_update(stream->hash_ctx, buffer, len); | 
| 1410 |  |  |  |  |  |  |  | 
| 1411 | 62 |  |  |  |  |  | stream->received_bytes += len; | 
| 1412 |  |  |  |  |  |  |  | 
| 1413 | 62 | 50 |  |  |  |  | if (stream->received_bytes > stream->declared_size) | 
| 1414 | 0 |  |  |  |  |  | return git_odb_stream__invalid_length(stream, | 
| 1415 |  |  |  |  |  |  | "stream_write()"); | 
| 1416 |  |  |  |  |  |  |  | 
| 1417 | 62 |  |  |  |  |  | return stream->write(stream, buffer, len); | 
| 1418 |  |  |  |  |  |  | } | 
| 1419 |  |  |  |  |  |  |  | 
| 1420 | 63 |  |  |  |  |  | int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) | 
| 1421 |  |  |  |  |  |  | { | 
| 1422 | 63 | 50 |  |  |  |  | if (stream->received_bytes != stream->declared_size) | 
| 1423 | 0 |  |  |  |  |  | return git_odb_stream__invalid_length(stream, | 
| 1424 |  |  |  |  |  |  | "stream_finalize_write()"); | 
| 1425 |  |  |  |  |  |  |  | 
| 1426 | 63 |  |  |  |  |  | git_hash_final(out, stream->hash_ctx); | 
| 1427 |  |  |  |  |  |  |  | 
| 1428 | 63 | 100 |  |  |  |  | if (git_odb__freshen(stream->backend->odb, out)) | 
| 1429 | 20 |  |  |  |  |  | return 0; | 
| 1430 |  |  |  |  |  |  |  | 
| 1431 | 43 |  |  |  |  |  | return stream->finalize_write(stream, out); | 
| 1432 |  |  |  |  |  |  | } | 
| 1433 |  |  |  |  |  |  |  | 
| 1434 | 0 |  |  |  |  |  | int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len) | 
| 1435 |  |  |  |  |  |  | { | 
| 1436 | 0 |  |  |  |  |  | return stream->read(stream, buffer, len); | 
| 1437 |  |  |  |  |  |  | } | 
| 1438 |  |  |  |  |  |  |  | 
| 1439 | 63 |  |  |  |  |  | void git_odb_stream_free(git_odb_stream *stream) | 
| 1440 |  |  |  |  |  |  | { | 
| 1441 | 63 | 50 |  |  |  |  | if (stream == NULL) | 
| 1442 | 0 |  |  |  |  |  | return; | 
| 1443 |  |  |  |  |  |  |  | 
| 1444 | 63 |  |  |  |  |  | git_hash_ctx_cleanup(stream->hash_ctx); | 
| 1445 | 63 |  |  |  |  |  | git__free(stream->hash_ctx); | 
| 1446 | 63 |  |  |  |  |  | stream->free(stream); | 
| 1447 |  |  |  |  |  |  | } | 
| 1448 |  |  |  |  |  |  |  | 
| 1449 | 0 |  |  |  |  |  | int git_odb_open_rstream( | 
| 1450 |  |  |  |  |  |  | git_odb_stream **stream, | 
| 1451 |  |  |  |  |  |  | size_t *len, | 
| 1452 |  |  |  |  |  |  | git_object_t *type, | 
| 1453 |  |  |  |  |  |  | git_odb *db, | 
| 1454 |  |  |  |  |  |  | const git_oid *oid) | 
| 1455 |  |  |  |  |  |  | { | 
| 1456 | 0 |  |  |  |  |  | size_t i, reads = 0; | 
| 1457 | 0 |  |  |  |  |  | int error = GIT_ERROR; | 
| 1458 |  |  |  |  |  |  |  | 
| 1459 | 0 | 0 |  |  |  |  | assert(stream && db); | 
|  |  | 0 |  |  |  |  |  | 
| 1460 |  |  |  |  |  |  |  | 
| 1461 | 0 | 0 |  |  |  |  | for (i = 0; i < db->backends.length && error < 0; ++i) { | 
|  |  | 0 |  |  |  |  |  | 
| 1462 | 0 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1463 | 0 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1464 |  |  |  |  |  |  |  | 
| 1465 | 0 | 0 |  |  |  |  | if (b->readstream != NULL) { | 
| 1466 | 0 |  |  |  |  |  | ++reads; | 
| 1467 | 0 |  |  |  |  |  | error = b->readstream(stream, len, type, b, oid); | 
| 1468 |  |  |  |  |  |  | } | 
| 1469 |  |  |  |  |  |  | } | 
| 1470 |  |  |  |  |  |  |  | 
| 1471 | 0 | 0 |  |  |  |  | if (error == GIT_PASSTHROUGH) | 
| 1472 | 0 |  |  |  |  |  | error = 0; | 
| 1473 | 0 | 0 |  |  |  |  | if (error < 0 && !reads) | 
|  |  | 0 |  |  |  |  |  | 
| 1474 | 0 |  |  |  |  |  | error = git_odb__error_unsupported_in_backend("read object streamed"); | 
| 1475 |  |  |  |  |  |  |  | 
| 1476 | 0 |  |  |  |  |  | return error; | 
| 1477 |  |  |  |  |  |  | } | 
| 1478 |  |  |  |  |  |  |  | 
| 1479 | 0 |  |  |  |  |  | int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload) | 
| 1480 |  |  |  |  |  |  | { | 
| 1481 | 0 |  |  |  |  |  | size_t i, writes = 0; | 
| 1482 | 0 |  |  |  |  |  | int error = GIT_ERROR; | 
| 1483 |  |  |  |  |  |  |  | 
| 1484 | 0 | 0 |  |  |  |  | assert(out && db); | 
|  |  | 0 |  |  |  |  |  | 
| 1485 |  |  |  |  |  |  |  | 
| 1486 | 0 | 0 |  |  |  |  | for (i = 0; i < db->backends.length && error < 0; ++i) { | 
|  |  | 0 |  |  |  |  |  | 
| 1487 | 0 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1488 | 0 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1489 |  |  |  |  |  |  |  | 
| 1490 |  |  |  |  |  |  | /* we don't write in alternates! */ | 
| 1491 | 0 | 0 |  |  |  |  | if (internal->is_alternate) | 
| 1492 | 0 |  |  |  |  |  | continue; | 
| 1493 |  |  |  |  |  |  |  | 
| 1494 | 0 | 0 |  |  |  |  | if (b->writepack != NULL) { | 
| 1495 | 0 |  |  |  |  |  | ++writes; | 
| 1496 | 0 |  |  |  |  |  | error = b->writepack(out, b, db, progress_cb, progress_payload); | 
| 1497 |  |  |  |  |  |  | } | 
| 1498 |  |  |  |  |  |  | } | 
| 1499 |  |  |  |  |  |  |  | 
| 1500 | 0 | 0 |  |  |  |  | if (error == GIT_PASSTHROUGH) | 
| 1501 | 0 |  |  |  |  |  | error = 0; | 
| 1502 | 0 | 0 |  |  |  |  | if (error < 0 && !writes) | 
|  |  | 0 |  |  |  |  |  | 
| 1503 | 0 |  |  |  |  |  | error = git_odb__error_unsupported_in_backend("write pack"); | 
| 1504 |  |  |  |  |  |  |  | 
| 1505 | 0 |  |  |  |  |  | return error; | 
| 1506 |  |  |  |  |  |  | } | 
| 1507 |  |  |  |  |  |  |  | 
| 1508 | 0 |  |  |  |  |  | void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len) | 
| 1509 |  |  |  |  |  |  | { | 
| 1510 |  |  |  |  |  |  | GIT_UNUSED(backend); | 
| 1511 | 0 |  |  |  |  |  | return git__malloc(len); | 
| 1512 |  |  |  |  |  |  | } | 
| 1513 |  |  |  |  |  |  |  | 
| 1514 |  |  |  |  |  |  | #ifndef GIT_DEPRECATE_HARD | 
| 1515 | 0 |  |  |  |  |  | void *git_odb_backend_malloc(git_odb_backend *backend, size_t len) | 
| 1516 |  |  |  |  |  |  | { | 
| 1517 | 0 |  |  |  |  |  | return git_odb_backend_data_alloc(backend, len); | 
| 1518 |  |  |  |  |  |  | } | 
| 1519 |  |  |  |  |  |  | #endif | 
| 1520 |  |  |  |  |  |  |  | 
| 1521 | 0 |  |  |  |  |  | void git_odb_backend_data_free(git_odb_backend *backend, void *data) | 
| 1522 |  |  |  |  |  |  | { | 
| 1523 |  |  |  |  |  |  | GIT_UNUSED(backend); | 
| 1524 | 0 |  |  |  |  |  | git__free(data); | 
| 1525 | 0 |  |  |  |  |  | } | 
| 1526 |  |  |  |  |  |  |  | 
| 1527 | 176 |  |  |  |  |  | int git_odb_refresh(struct git_odb *db) | 
| 1528 |  |  |  |  |  |  | { | 
| 1529 |  |  |  |  |  |  | size_t i; | 
| 1530 | 176 | 50 |  |  |  |  | assert(db); | 
| 1531 |  |  |  |  |  |  |  | 
| 1532 | 533 | 100 |  |  |  |  | for (i = 0; i < db->backends.length; ++i) { | 
| 1533 | 357 |  |  |  |  |  | backend_internal *internal = git_vector_get(&db->backends, i); | 
| 1534 | 357 |  |  |  |  |  | git_odb_backend *b = internal->backend; | 
| 1535 |  |  |  |  |  |  |  | 
| 1536 | 357 | 100 |  |  |  |  | if (b->refresh != NULL) { | 
| 1537 | 176 |  |  |  |  |  | int error = b->refresh(b); | 
| 1538 | 176 | 50 |  |  |  |  | if (error < 0) | 
| 1539 | 0 |  |  |  |  |  | return error; | 
| 1540 |  |  |  |  |  |  | } | 
| 1541 |  |  |  |  |  |  | } | 
| 1542 |  |  |  |  |  |  |  | 
| 1543 | 176 |  |  |  |  |  | return 0; | 
| 1544 |  |  |  |  |  |  | } | 
| 1545 |  |  |  |  |  |  |  | 
| 1546 | 0 |  |  |  |  |  | int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual) | 
| 1547 |  |  |  |  |  |  | { | 
| 1548 |  |  |  |  |  |  | char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1]; | 
| 1549 |  |  |  |  |  |  |  | 
| 1550 | 0 |  |  |  |  |  | git_oid_tostr(expected_oid, sizeof(expected_oid), expected); | 
| 1551 | 0 |  |  |  |  |  | git_oid_tostr(actual_oid, sizeof(actual_oid), actual); | 
| 1552 |  |  |  |  |  |  |  | 
| 1553 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s", | 
| 1554 |  |  |  |  |  |  | expected_oid, actual_oid); | 
| 1555 |  |  |  |  |  |  |  | 
| 1556 | 0 |  |  |  |  |  | return GIT_EMISMATCH; | 
| 1557 |  |  |  |  |  |  | } | 
| 1558 |  |  |  |  |  |  |  | 
| 1559 | 1638 |  |  |  |  |  | int git_odb__error_notfound( | 
| 1560 |  |  |  |  |  |  | const char *message, const git_oid *oid, size_t oid_len) | 
| 1561 |  |  |  |  |  |  | { | 
| 1562 | 1638 | 50 |  |  |  |  | if (oid != NULL) { | 
| 1563 |  |  |  |  |  |  | char oid_str[GIT_OID_HEXSZ + 1]; | 
| 1564 | 1638 |  |  |  |  |  | git_oid_tostr(oid_str, oid_len+1, oid); | 
| 1565 | 1638 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)", | 
| 1566 |  |  |  |  |  |  | message, (int) oid_len, oid_str); | 
| 1567 |  |  |  |  |  |  | } else | 
| 1568 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "object not found - %s", message); | 
| 1569 |  |  |  |  |  |  |  | 
| 1570 | 1638 |  |  |  |  |  | return GIT_ENOTFOUND; | 
| 1571 |  |  |  |  |  |  | } | 
| 1572 |  |  |  |  |  |  |  | 
| 1573 | 0 |  |  |  |  |  | static int error_null_oid(int error, const char *message) | 
| 1574 |  |  |  |  |  |  | { | 
| 1575 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message); | 
| 1576 | 0 |  |  |  |  |  | return error; | 
| 1577 |  |  |  |  |  |  | } | 
| 1578 |  |  |  |  |  |  |  | 
| 1579 | 0 |  |  |  |  |  | int git_odb__error_ambiguous(const char *message) | 
| 1580 |  |  |  |  |  |  | { | 
| 1581 | 0 |  |  |  |  |  | git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message); | 
| 1582 | 0 |  |  |  |  |  | return GIT_EAMBIGUOUS; | 
| 1583 |  |  |  |  |  |  | } | 
| 1584 |  |  |  |  |  |  |  | 
| 1585 | 0 |  |  |  |  |  | int git_odb_init_backend(git_odb_backend *backend, unsigned int version) | 
| 1586 |  |  |  |  |  |  | { | 
| 1587 | 0 | 0 |  |  |  |  | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | 
| 1588 |  |  |  |  |  |  | backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT); | 
| 1589 | 0 |  |  |  |  |  | return 0; | 
| 1590 |  |  |  |  |  |  | } |