source src/tree.c
| Line | Flow | Count | Block(s) | Source |
|---|---|---|---|---|
| 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 "tree.h" | ||
| 9 | - | |||
| 10 | - | #include "commit.h" | ||
| 11 | - | #include "git2/repository.h" | ||
| 12 | - | #include "git2/object.h" | ||
| 13 | - | #include "futils.h" | ||
| 14 | - | #include "tree-cache.h" | ||
| 15 | - | #include "index.h" | ||
| 16 | - | |||
| 17 | - | #define DEFAULT_TREE_SIZE 16 | ||
| 18 | - | #define MAX_FILEMODE_BYTES 6 | ||
| 19 | - | |||
| 20 | - | #define TREE_ENTRY_CHECK_NAMELEN(n) \ | ||
| 21 | - | if (n > UINT16_MAX) { git_error_set(GIT_ERROR_INVALID, "tree entry path too long"); } | ||
| 22 | - | |||
| 23 | 2834 | 2 | static bool valid_filemode(const int filemode) | |
| 24 | - | { | ||
| 25 | 2834 | 9 | return (filemode == GIT_FILEMODE_TREE | |
| 26 | 2615 | 3 | || filemode == GIT_FILEMODE_BLOB | |
| 27 | 26 | 4 | || filemode == GIT_FILEMODE_BLOB_EXECUTABLE | |
| 28 | 23 | 5 | || filemode == GIT_FILEMODE_LINK | |
| 29 | 2834 | 2,6-8 | || filemode == GIT_FILEMODE_COMMIT); | |
| 30 | - | } | ||
| 31 | - | |||
| 32 | 6539 | 2 | GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) | |
| 33 | - | { | ||
| 34 | - | /* Tree bits set, but it's not a commit */ | ||
| 35 | 6539 | 2 | if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_TREE) | |
| 36 | 413 | 3 | return GIT_FILEMODE_TREE; | |
| 37 | - | |||
| 38 | - | /* If any of the x bits are set */ | ||
| 39 | 6126 | 4 | if (GIT_PERMS_IS_EXEC(filemode)) | |
| 40 | 24 | 5 | return GIT_FILEMODE_BLOB_EXECUTABLE; | |
| 41 | - | |||
| 42 | - | /* 16XXXX means commit */ | ||
| 43 | 6102 | 6 | if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_COMMIT) | |
| 44 | 34 | 7 | return GIT_FILEMODE_COMMIT; | |
| 45 | - | |||
| 46 | - | /* 12XXXX means symlink */ | ||
| 47 | 6068 | 8 | if (GIT_MODE_TYPE(filemode) == GIT_FILEMODE_LINK) | |
| 48 | 126 | 9 | return GIT_FILEMODE_LINK; | |
| 49 | - | |||
| 50 | - | /* Otherwise, return a blob */ | ||
| 51 | 5942 | 10 | return GIT_FILEMODE_BLOB; | |
| 52 | - | } | ||
| 53 | - | |||
| 54 | 2830 | 2 | static int valid_entry_name(git_repository *repo, const char *filename) | |
| 55 | - | { | ||
| 56 | 2830 | 2,4 | return *filename != '\0' && | |
| 57 | 2829 | 3 | git_path_isvalid(repo, filename, 0, | |
| 58 | - | GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH); | ||
| 59 | - | } | ||
| 60 | - | |||
| 61 | 26652 | 2 | static int entry_sort_cmp(const void *a, const void *b) | |
| 62 | - | { | ||
| 63 | 26652 | 2 | const git_tree_entry *e1 = (const git_tree_entry *)a; | |
| 64 | 26652 | 2 | const git_tree_entry *e2 = (const git_tree_entry *)b; | |
| 65 | - | |||
| 66 | 26652 | 3,3,4,4 | return git_path_cmp( | |
| 67 | 26652 | 3,4 | e1->filename, e1->filename_len, git_tree_entry__is_tree(e1), | |
| 68 | 26652 | 2,3 | e2->filename, e2->filename_len, git_tree_entry__is_tree(e2), | |
| 69 | - | git__strncmp); | ||
| 70 | - | } | ||
| 71 | - | |||
| 72 | ##### | 2 | int git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2) | |
| 73 | - | { | ||
| 74 | ##### | 2 | return entry_sort_cmp(e1, e2); | |
| 75 | - | } | ||
| 76 | - | |||
| 77 | - | /** | ||
| 78 | - | * Allocate a new self-contained entry, with enough space after it to | ||
| 79 | - | * store the filename and the id. | ||
| 80 | - | */ | ||
| 81 | ![]() |
7193 | 2 | static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id) |
| 82 | - | { | ||
| 83 | 7193 | 2 | git_tree_entry *entry = NULL; | |
| 84 | - | size_t tree_len; | ||
| 85 | - | |||
| 86 | 7193 | 2,3 | TREE_ENTRY_CHECK_NAMELEN(filename_len); | |
| 87 | - | |||
| 88 | 7193 | 4-6,8,11 | if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || | |
| 89 | 7193 | 7,9 | GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || | |
| 90 | 7193 | 10,12 | GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ)) | |
| 91 | ##### | 13 | return NULL; | |
| 92 | - | |||
| 93 | 7193 | 14 | entry = git__calloc(1, tree_len); | |
| 94 | 7193 | 15 | if (!entry) | |
| 95 | ##### | 16 | return NULL; | |
| 96 | - | |||
| 97 | - | { | ||
| 98 | - | char *filename_ptr; | ||
| 99 | - | void *id_ptr; | ||
| 100 | - | |||
| 101 | 7193 | 17 | filename_ptr = ((char *) entry) + sizeof(git_tree_entry); | |
| 102 | 7193 | 17 | memcpy(filename_ptr, filename, filename_len); | |
| 103 | 7193 | 17 | entry->filename = filename_ptr; | |
| 104 | - | |||
| 105 | 7193 | 17 | id_ptr = filename_ptr + filename_len + 1; | |
| 106 | 7193 | 17 | git_oid_cpy(id_ptr, id); | |
| 107 | 7193 | 18 | entry->oid = id_ptr; | |
| 108 | - | } | ||
| 109 | - | |||
| 110 | 7193 | 18 | entry->filename_len = (uint16_t)filename_len; | |
| 111 | - | |||
| 112 | 7193 | 18 | return entry; | |
| 113 | - | } | ||
| 114 | - | |||
| 115 | - | struct tree_key_search { | ||
| 116 | - | const char *filename; | ||
| 117 | - | uint16_t filename_len; | ||
| 118 | - | }; | ||
| 119 | - | |||
| 120 | 28259 | 2 | static int homing_search_cmp(const void *key, const void *array_member) | |
| 121 | - | { | ||
| 122 | 28259 | 2 | const struct tree_key_search *ksearch = key; | |
| 123 | 28259 | 2 | const git_tree_entry *entry = array_member; | |
| 124 | - | |||
| 125 | 28259 | 2 | const uint16_t len1 = ksearch->filename_len; | |
| 126 | 28259 | 2 | const uint16_t len2 = entry->filename_len; | |
| 127 | - | |||
| 128 | 28259 | 2 | return memcmp( | |
| 129 | 28259 | 2 | ksearch->filename, | |
| 130 | 28259 | 2 | entry->filename, | |
| 131 | 28259 | 2 | len1 < len2 ? len1 : len2 | |
| 132 | - | ); | ||
| 133 | - | } | ||
| 134 | - | |||
| 135 | - | /* | ||
| 136 | - | * Search for an entry in a given tree. | ||
| 137 | - | * | ||
| 138 | - | * Note that this search is performed in two steps because | ||
| 139 | - | * of the way tree entries are sorted internally in git: | ||
| 140 | - | * | ||
| 141 | - | * Entries in a tree are not sorted alphabetically; two entries | ||
| 142 | - | * with the same root prefix will have different positions | ||
| 143 | - | * depending on whether they are folders (subtrees) or normal files. | ||
| 144 | - | * | ||
| 145 | - | * Consequently, it is not possible to find an entry on the tree | ||
| 146 | - | * with a binary search if you don't know whether the filename | ||
| 147 | - | * you're looking for is a folder or a normal file. | ||
| 148 | - | * | ||
| 149 | - | * To work around this, we first perform a homing binary search | ||
| 150 | - | * on the tree, using the minimal length root prefix of our filename. | ||
| 151 | - | * Once the comparisons for this homing search start becoming | ||
| 152 | - | * ambiguous because of folder vs file sorting, we look linearly | ||
| 153 | - | * around the area for our target file. | ||
| 154 | - | */ | ||
| 155 | ![]() |
7799 | 2 | static int tree_key_search( |
| 156 | - | size_t *at_pos, | ||
| 157 | - | const git_tree *tree, | ||
| 158 | - | const char *filename, | ||
| 159 | - | size_t filename_len) | ||
| 160 | - | { | ||
| 161 | - | struct tree_key_search ksearch; | ||
| 162 | - | const git_tree_entry *entry; | ||
| 163 | - | size_t homing, i; | ||
| 164 | - | |||
| 165 | 7799 | 2,3 | TREE_ENTRY_CHECK_NAMELEN(filename_len); | |
| 166 | - | |||
| 167 | 7799 | 4 | ksearch.filename = filename; | |
| 168 | 7799 | 4 | ksearch.filename_len = (uint16_t)filename_len; | |
| 169 | - | |||
| 170 | - | /* Initial homing search; find an entry on the tree with | ||
| 171 | - | * the same prefix as the filename we're looking for */ | ||
| 172 | - | |||
| 173 | 7799 | 4,5 | if (git_array_search(&homing, | |
| 174 | - | tree->entries, &homing_search_cmp, &ksearch) < 0) | ||
| 175 | 192 | 6 | return GIT_ENOTFOUND; /* just a signal error; not passed back to user */ | |
| 176 | - | |||
| 177 | - | /* We found a common prefix. Look forward as long as | ||
| 178 | - | * there are entries that share the common prefix */ | ||
| 179 | 10733 | 7,19,20 | for (i = homing; i < tree->entries.size; ++i) { | |
| 180 | 7860 | 8-10 | entry = git_array_get(tree->entries, i); | |
| 181 | - | |||
| 182 | 7860 | 11,12 | if (homing_search_cmp(&ksearch, entry) < 0) | |
| 183 | 246 | 13 | break; | |
| 184 | - | |||
| 185 | 7614 | 14,15 | if (entry->filename_len == filename_len && | |
| 186 | 4488 | 15 | memcmp(filename, entry->filename, filename_len) == 0) { | |
| 187 | 4488 | 16 | if (at_pos) | |
| 188 | 4488 | 17 | *at_pos = i; | |
| 189 | - | |||
| 190 | 4488 | 18 | return 0; | |
| 191 | - | } | ||
| 192 | - | } | ||
| 193 | - | |||
| 194 | - | /* If we haven't found our filename yet, look backwards | ||
| 195 | - | * too as long as we have entries with the same prefix */ | ||
| 196 | 3119 | 21 | if (homing > 0) { | |
| 197 | 3119 | 22 | i = homing - 1; | |
| 198 | - | |||
| 199 | - | do { | ||
| 200 | 3119 | 23-25 | entry = git_array_get(tree->entries, i); | |
| 201 | - | |||
| 202 | 3119 | 26,27 | if (homing_search_cmp(&ksearch, entry) > 0) | |
| 203 | 6 | 28 | break; | |
| 204 | - | |||
| 205 | 3113 | 29,30 | if (entry->filename_len == filename_len && | |
| 206 | 3112 | 30 | memcmp(filename, entry->filename, filename_len) == 0) { | |
| 207 | 3112 | 31 | if (at_pos) | |
| 208 | 3112 | 32 | *at_pos = i; | |
| 209 | - | |||
| 210 | 3112 | 33 | return 0; | |
| 211 | - | } | ||
| 212 | 1 | 34 | } while (i-- > 0); | |
| 213 | - | } | ||
| 214 | - | |||
| 215 | - | /* The filename doesn't exist at all */ | ||
| 216 | 7 | 35 | return GIT_ENOTFOUND; | |
| 217 | - | } | ||
| 218 | - | |||
| 219 | 182641 | 2 | void git_tree_entry_free(git_tree_entry *entry) | |
| 220 | - | { | ||
| 221 | 182641 | 2 | if (entry == NULL) | |
| 222 | 182641 | 3,5 | return; | |
| 223 | - | |||
| 224 | 7193 | 4 | git__free(entry); | |
| 225 | - | } | ||
| 226 | - | |||
| 227 | 4228 | 2 | int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) | |
| 228 | - | { | ||
| 229 | - | git_tree_entry *cpy; | ||
| 230 | - | |||
| 231 | 4228 | 2,3 | assert(source); | |
| 232 | - | |||
| 233 | 4228 | 4 | cpy = alloc_entry(source->filename, source->filename_len, source->oid); | |
| 234 | 4228 | 5 | if (cpy == NULL) | |
| 235 | ##### | 6 | return -1; | |
| 236 | - | |||
| 237 | 4228 | 7 | cpy->attr = source->attr; | |
| 238 | - | |||
| 239 | 4228 | 7 | *dest = cpy; | |
| 240 | 4228 | 7 | return 0; | |
| 241 | - | } | ||
| 242 | - | |||
| 243 | 25707 | 2 | void git_tree__free(void *_tree) | |
| 244 | - | { | ||
| 245 | 25707 | 2 | git_tree *tree = _tree; | |
| 246 | - | |||
| 247 | 25707 | 2 | git_odb_object_free(tree->odb_obj); | |
| 248 | 25707 | 3 | git_array_clear(tree->entries); | |
| 249 | 25707 | 4 | git__free(tree); | |
| 250 | 25707 | 5 | } | |
| 251 | - | |||
| 252 | 6539 | 2 | git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) | |
| 253 | - | { | ||
| 254 | 6539 | 2 | return normalize_filemode(entry->attr); | |
| 255 | - | } | ||
| 256 | - | |||
| 257 | 1 | 2 | git_filemode_t git_tree_entry_filemode_raw(const git_tree_entry *entry) | |
| 258 | - | { | ||
| 259 | 1 | 2 | return entry->attr; | |
| 260 | - | } | ||
| 261 | - | |||
| 262 | 2817 | 2 | const char *git_tree_entry_name(const git_tree_entry *entry) | |
| 263 | - | { | ||
| 264 | 2817 | 2,3 | assert(entry); | |
| 265 | 2817 | 4 | return entry->filename; | |
| 266 | - | } | ||
| 267 | - | |||
| 268 | 4264 | 2 | const git_oid *git_tree_entry_id(const git_tree_entry *entry) | |
| 269 | - | { | ||
| 270 | 4264 | 2,3 | assert(entry); | |
| 271 | 4264 | 4 | return entry->oid; | |
| 272 | - | } | ||
| 273 | - | |||
| 274 | 5446 | 2 | git_object_t git_tree_entry_type(const git_tree_entry *entry) | |
| 275 | - | { | ||
| 276 | 5446 | 2,3 | assert(entry); | |
| 277 | - | |||
| 278 | 5446 | 4 | if (S_ISGITLINK(entry->attr)) | |
| 279 | 10 | 5 | return GIT_OBJECT_COMMIT; | |
| 280 | 5436 | 6 | else if (S_ISDIR(entry->attr)) | |
| 281 | 246 | 7 | return GIT_OBJECT_TREE; | |
| 282 | - | else | ||
| 283 | 5190 | 8 | return GIT_OBJECT_BLOB; | |
| 284 | - | } | ||
| 285 | - | |||
| 286 | ![]() |
3461 | 2 | int git_tree_entry_to_object( |
| 287 | - | git_object **object_out, | ||
| 288 | - | git_repository *repo, | ||
| 289 | - | const git_tree_entry *entry) | ||
| 290 | - | { | ||
| 291 | 3461 | 2-4 | assert(entry && object_out); | |
| 292 | 3461 | 5 | return git_object_lookup(object_out, repo, entry->oid, GIT_OBJECT_ANY); | |
| 293 | - | } | ||
| 294 | - | |||
| 295 | 7799 | 2 | static const git_tree_entry *entry_fromname( | |
| 296 | - | const git_tree *tree, const char *name, size_t name_len) | ||
| 297 | - | { | ||
| 298 | - | size_t idx; | ||
| 299 | - | |||
| 300 | 7799 | 2,3 | if (tree_key_search(&idx, tree, name, name_len) < 0) | |
| 301 | 199 | 4 | return NULL; | |
| 302 | - | |||
| 303 | 7600 | 5 | return git_array_get(tree->entries, idx); | |
| 304 | - | } | ||
| 305 | - | |||
| 306 | ![]() |
41 | 2 | const git_tree_entry *git_tree_entry_byname( |
| 307 | - | const git_tree *tree, const char *filename) | ||
| 308 | - | { | ||
| 309 | 41 | 2-4 | assert(tree && filename); | |
| 310 | - | |||
| 311 | 41 | 5 | return entry_fromname(tree, filename, strlen(filename)); | |
| 312 | - | } | ||
| 313 | - | |||
| 314 | 8090 | 2 | const git_tree_entry *git_tree_entry_byindex( | |
| 315 | - | const git_tree *tree, size_t idx) | ||
| 316 | - | { | ||
| 317 | 8090 | 2,3 | assert(tree); | |
| 318 | 8090 | 4 | return git_array_get(tree->entries, idx); | |
| 319 | - | } | ||
| 320 | - | |||
| 321 | ![]() |
##### | 2 | const git_tree_entry *git_tree_entry_byid( |
| 322 | - | const git_tree *tree, const git_oid *id) | ||
| 323 | - | { | ||
| 324 | - | size_t i; | ||
| 325 | - | const git_tree_entry *e; | ||
| 326 | - | |||
| 327 | ##### | 2,3 | assert(tree); | |
| 328 | - | |||
| 329 | ##### | 4,7-9 | git_array_foreach(tree->entries, i, e) { | |
| 330 | ##### | 5 | if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0) | |
| 331 | ##### | 6 | return e; | |
| 332 | - | } | ||
| 333 | - | |||
| 334 | ##### | 10 | return NULL; | |
| 335 | - | } | ||
| 336 | - | |||
| 337 | 3387 | 2 | size_t git_tree_entrycount(const git_tree *tree) | |
| 338 | - | { | ||
| 339 | 3387 | 2,3 | assert(tree); | |
| 340 | 3387 | 4 | return tree->entries.size; | |
| 341 | - | } | ||
| 342 | - | |||
| 343 | 35 | 2 | size_t git_treebuilder_entrycount(git_treebuilder *bld) | |
| 344 | - | { | ||
| 345 | 35 | 2,3 | assert(bld); | |
| 346 | - | |||
| 347 | 35 | 4 | return git_strmap_size(bld->map); | |
| 348 | - | } | ||
| 349 | - | |||
| 350 | 49 | 2 | static int tree_error(const char *str, const char *path) | |
| 351 | - | { | ||
| 352 | 49 | 2 | if (path) | |
| 353 | 39 | 3 | git_error_set(GIT_ERROR_TREE, "%s - %s", str, path); | |
| 354 | - | else | ||
| 355 | 10 | 4 | git_error_set(GIT_ERROR_TREE, "%s", str); | |
| 356 | 49 | 5 | return -1; | |
| 357 | - | } | ||
| 358 | - | |||
| 359 | ![]() |
- | 2 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files)static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, const char **buffer_out) |
| 360 | - | { | ||
| 361 | - | int32_t mode; | ||
| 362 | - | int error; | ||
| 363 | - | |||
| 364 | - | 2-4 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) if (!buffer_len || git__isspace(*buffer)) | |
| 365 | - | 5 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) return -1; | |
| 366 | - | |||
| 367 | - | 6,7 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) if ((error = git__strntol32(&mode, buffer, buffer_len, buffer_out, 8)) < 0) | |
| 368 | - | 8 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) return error; | |
| 369 | - | |||
| 370 | - | 9,10 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) if (mode < 0 || mode > UINT16_MAX) | |
| 371 | - | 11 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) return -1; | |
| 372 | - | |||
| 373 | - | 12 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) *mode_out = mode; | |
| 374 | - | |||
| 375 | - | 12 | suppressed: function cannot be solved parse_mode (automatic due to inconsistent arc counts in .gcda files) return 0; | |
| 376 | - | } | ||
| 377 | - | |||
| 378 | ![]() |
- | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files)int git_tree__parse_raw(void *_tree, const char *data, size_t size) |
| 379 | - | { | ||
| 380 | - | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) git_tree *tree = _tree; | |
| 381 | - | const char *buffer; | ||
| 382 | - | const char *buffer_end; | ||
| 383 | - | |||
| 384 | - | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) buffer = data; | |
| 385 | - | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) buffer_end = buffer + size; | |
| 386 | - | |||
| 387 | - | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) tree->odb_obj = NULL; | |
| 388 | - | 2 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE); | |
| 389 | - | 3,4 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ARRAY(tree->entries); | |
| 390 | - | |||
| 391 | - | 5,30 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) while (buffer < buffer_end) { | |
| 392 | - | git_tree_entry *entry; | ||
| 393 | - | size_t filename_len; | ||
| 394 | - | const char *nul; | ||
| 395 | - | uint16_t attr; | ||
| 396 | - | |||
| 397 | - | 6-8 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer) | |
| 398 | - | 9,29 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return tree_error("failed to parse tree: can't parse filemode", NULL); | |
| 399 | - | |||
| 400 | - | 10,11 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) if (buffer >= buffer_end || (*buffer++) != ' ') | |
| 401 | - | 12 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return tree_error("failed to parse tree: missing space after filemode", NULL); | |
| 402 | - | |||
| 403 | - | 13 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL) | |
| 404 | - | 14 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return tree_error("failed to parse tree: object is corrupted", NULL); | |
| 405 | - | |||
| 406 | - | 15,16 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX) | |
| 407 | - | 17 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return tree_error("failed to parse tree: can't parse filename", NULL); | |
| 408 | - | |||
| 409 | - | 18 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ) | |
| 410 | - | 19 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return tree_error("failed to parse tree: can't parse OID", NULL); | |
| 411 | - | |||
| 412 | - | /* Allocate the entry */ | ||
| 413 | - | { | ||
| 414 | - | 20-25 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) entry = git_array_alloc(tree->entries); | |
| 415 | - | 26,27 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ALLOC(entry); | |
| 416 | - | |||
| 417 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) entry->attr = attr; | |
| 418 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) entry->filename_len = (uint16_t)filename_len; | |
| 419 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) entry->filename = buffer; | |
| 420 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) entry->oid = (git_oid *) ((char *) buffer + filename_len + 1); | |
| 421 | - | } | ||
| 422 | - | |||
| 423 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) buffer += filename_len + 1; | |
| 424 | - | 28 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) buffer += GIT_OID_RAWSZ; | |
| 425 | - | } | ||
| 426 | - | |||
| 427 | - | 31 | suppressed: function cannot be solved git_tree__parse_raw (automatic due to inconsistent arc counts in .gcda files) return 0; | |
| 428 | - | } | ||
| 429 | - | |||
| 430 | ![]() |
25676 | 2 | int git_tree__parse(void *_tree, git_odb_object *odb_obj) |
| 431 | - | { | ||
| 432 | 25676 | 2 | git_tree *tree = _tree; | |
| 433 | - | |||
| 434 | 25682 | 2,4,5 | if ((git_tree__parse_raw(tree, | |
| 435 | 25680 | 3 | git_odb_object_data(odb_obj), | |
| 436 | - | git_odb_object_size(odb_obj))) < 0) | ||
| 437 | ##### | 6 | return -1; | |
| 438 | - | |||
| 439 | 25685 | 7,8 | if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0) | |
| 440 | ##### | 9 | return -1; | |
| 441 | - | |||
| 442 | 25685 | 10 | return 0; | |
| 443 | - | } | ||
| 444 | - | |||
| 445 | ![]() |
5 | 2 | static size_t find_next_dir(const char *dirname, git_index *index, size_t start) |
| 446 | - | { | ||
| 447 | 5 | 2 | size_t dirlen, i, entries = git_index_entrycount(index); | |
| 448 | - | |||
| 449 | 5 | 3 | dirlen = strlen(dirname); | |
| 450 | 23 | 3,9,10 | for (i = start; i < entries; ++i) { | |
| 451 | 18 | 4 | const git_index_entry *entry = git_index_get_byindex(index, i); | |
| 452 | 18 | 5,6 | if (strlen(entry->path) < dirlen || | |
| 453 | 18 | 6,7 | memcmp(entry->path, dirname, dirlen) || | |
| 454 | 18 | 8 | (dirlen > 0 && entry->path[dirlen] != '/')) { | |
| 455 | - | break; | ||
| 456 | - | } | ||
| 457 | - | } | ||
| 458 | - | |||
| 459 | 5 | 11 | return i; | |
| 460 | - | } | ||
| 461 | - | |||
| 462 | 2786 | 2 | static git_object_t otype_from_mode(git_filemode_t filemode) | |
| 463 | - | { | ||
| 464 | 2786 | 2 | switch (filemode) { | |
| 465 | - | case GIT_FILEMODE_TREE: | ||
| 466 | 205 | 3 | return GIT_OBJECT_TREE; | |
| 467 | - | case GIT_FILEMODE_COMMIT: | ||
| 468 | ##### | 4 | return GIT_OBJECT_COMMIT; | |
| 469 | - | default: | ||
| 470 | 2581 | 5 | return GIT_OBJECT_BLOB; | |
| 471 | - | } | ||
| 472 | - | } | ||
| 473 | - | |||
| 474 | ![]() |
2834 | 2 | static int check_entry(git_repository *repo, const char *filename, const git_oid *id, git_filemode_t filemode) |
| 475 | - | { | ||
| 476 | 2834 | 2,3 | if (!valid_filemode(filemode)) | |
| 477 | 4 | 4 | return tree_error("failed to insert entry: invalid filemode for file", filename); | |
| 478 | - | |||
| 479 | 2830 | 5,6 | if (!valid_entry_name(repo, filename)) | |
| 480 | 27 | 7 | return tree_error("failed to insert entry: invalid name for a tree entry", filename); | |
| 481 | - | |||
| 482 | 2803 | 8,9 | if (git_oid_is_zero(id)) | |
| 483 | 1 | 10 | return tree_error("failed to insert entry: invalid null OID", filename); | |
| 484 | - | |||
| 485 | 2802 | 11,14 | if (filemode != GIT_FILEMODE_COMMIT && | |
| 486 | 2786 | 12,13 | !git_object__is_valid(repo, id, otype_from_mode(filemode))) | |
| 487 | 7 | 15 | return tree_error("failed to insert entry: invalid object specified", filename); | |
| 488 | - | |||
| 489 | 2795 | 16 | return 0; | |
| 490 | - | } | ||
| 491 | - | |||
| 492 | ![]() |
1743 | 2 | static int append_entry( |
| 493 | - | git_treebuilder *bld, | ||
| 494 | - | const char *filename, | ||
| 495 | - | const git_oid *id, | ||
| 496 | - | git_filemode_t filemode, | ||
| 497 | - | bool validate) | ||
| 498 | - | { | ||
| 499 | - | git_tree_entry *entry; | ||
| 500 | 1743 | 2 | int error = 0; | |
| 501 | - | |||
| 502 | 1743 | 2-4 | if (validate && ((error = check_entry(bld->repo, filename, id, filemode)) < 0)) | |
| 503 | 15 | 5 | return error; | |
| 504 | - | |||
| 505 | 1728 | 6 | entry = alloc_entry(filename, strlen(filename), id); | |
| 506 | 1728 | 7,8 | GIT_ERROR_CHECK_ALLOC(entry); | |
| 507 | - | |||
| 508 | 1728 | 9 | entry->attr = (uint16_t)filemode; | |
| 509 | - | |||
| 510 | 1728 | 9,10 | if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { | |
| 511 | ##### | 11 | git_tree_entry_free(entry); | |
| 512 | ##### | 12 | git_error_set(GIT_ERROR_TREE, "failed to append entry %s to the tree builder", filename); | |
| 513 | ##### | 13 | return -1; | |
| 514 | - | } | ||
| 515 | - | |||
| 516 | 1728 | 14 | return 0; | |
| 517 | - | } | ||
| 518 | - | |||
| 519 | ![]() |
465 | 2 | static int write_tree( |
| 520 | - | git_oid *oid, | ||
| 521 | - | git_repository *repo, | ||
| 522 | - | git_index *index, | ||
| 523 | - | const char *dirname, | ||
| 524 | - | size_t start, | ||
| 525 | - | git_buf *shared_buf) | ||
| 526 | - | { | ||
| 527 | 465 | 2 | git_treebuilder *bld = NULL; | |
| 528 | 465 | 2 | size_t i, entries = git_index_entrycount(index); | |
| 529 | - | int error; | ||
| 530 | 465 | 3 | size_t dirname_len = strlen(dirname); | |
| 531 | - | const git_tree_cache *cache; | ||
| 532 | - | |||
| 533 | 465 | 3 | cache = git_tree_cache_get(index->tree, dirname); | |
| 534 | 465 | 4,5 | if (cache != NULL && cache->entry_count >= 0){ | |
| 535 | 5 | 6 | git_oid_cpy(oid, &cache->oid); | |
| 536 | 5 | 7,8 | return (int)find_next_dir(dirname, index, start); | |
| 537 | - | } | ||
| 538 | - | |||
| 539 | 460 | 9-11 | if ((error = git_treebuilder_new(&bld, repo, NULL)) < 0 || bld == NULL) | |
| 540 | ##### | 12 | return -1; | |
| 541 | - | |||
| 542 | - | /* | ||
| 543 | - | * This loop is unfortunate, but necessary. The index doesn't have | ||
| 544 | - | * any directores, so we need to handle that manually, and we | ||
| 545 | - | * need to keep track of the current position. | ||
| 546 | - | */ | ||
| 547 | 2004 | 13,41,42 | for (i = start; i < entries; ++i) { | |
| 548 | 1654 | 14 | const git_index_entry *entry = git_index_get_byindex(index, i); | |
| 549 | - | const char *filename, *next_slash; | ||
| 550 | - | |||
| 551 | - | /* | ||
| 552 | - | * If we've left our (sub)tree, exit the loop and return. The | ||
| 553 | - | * first check is an early out (and security for the | ||
| 554 | - | * third). The second check is a simple prefix comparison. The | ||
| 555 | - | * third check catches situations where there is a directory | ||
| 556 | - | * win32/sys and a file win32mmap.c. Without it, the following | ||
| 557 | - | * code believes there is a file win32/mmap.c | ||
| 558 | - | */ | ||
| 559 | 1654 | 15,16 | if (strlen(entry->path) < dirname_len || | |
| 560 | 1643 | 16,17 | memcmp(entry->path, dirname, dirname_len) || | |
| 561 | 346 | 18 | (dirname_len > 0 && entry->path[dirname_len] != '/')) { | |
| 562 | - | break; | ||
| 563 | - | } | ||
| 564 | - | |||
| 565 | 1561 | 19 | filename = entry->path + dirname_len; | |
| 566 | 1561 | 19 | if (*filename == '/') | |
| 567 | 342 | 20 | filename++; | |
| 568 | 1561 | 21 | next_slash = strchr(filename, '/'); | |
| 569 | 1561 | 21 | if (next_slash) { | |
| 570 | - | git_oid sub_oid; | ||
| 571 | - | int written; | ||
| 572 | - | char *subdir, *last_comp; | ||
| 573 | - | |||
| 574 | 134 | 22 | subdir = git__strndup(entry->path, next_slash - entry->path); | |
| 575 | 134 | 23,24 | GIT_ERROR_CHECK_ALLOC(subdir); | |
| 576 | - | |||
| 577 | - | /* Write out the subtree */ | ||
| 578 | 134 | 25 | written = write_tree(&sub_oid, repo, index, subdir, i, shared_buf); | |
| 579 | 134 | 26 | if (written < 0) { | |
| 580 | 2 | 27 | git__free(subdir); | |
| 581 | 16 | 36,37 | goto on_error; | |
| 582 | - | } else { | ||
| 583 | 132 | 28 | i = written - 1; /* -1 because of the loop increment */ | |
| 584 | - | } | ||
| 585 | - | |||
| 586 | - | /* | ||
| 587 | - | * We need to figure out what we want toinsert | ||
| 588 | - | * into this tree. If we're traversing | ||
| 589 | - | * deps/zlib/, then we only want to write | ||
| 590 | - | * 'zlib' into the tree. | ||
| 591 | - | */ | ||
| 592 | 132 | 28 | last_comp = strrchr(subdir, '/'); | |
| 593 | 132 | 28 | if (last_comp) { | |
| 594 | 79 | 29 | last_comp++; /* Get rid of the '/' */ | |
| 595 | - | } else { | ||
| 596 | 53 | 30 | last_comp = subdir; | |
| 597 | - | } | ||
| 598 | - | |||
| 599 | 132 | 31 | error = append_entry(bld, last_comp, &sub_oid, S_IFDIR, true); | |
| 600 | 132 | 32 | git__free(subdir); | |
| 601 | 132 | 33 | if (error < 0) | |
| 602 | 118 | 34,35 | goto on_error; | |
| 603 | - | } else { | ||
| 604 | 1427 | 38 | error = append_entry(bld, filename, &entry->id, entry->mode, true); | |
| 605 | 1427 | 39 | if (error < 0) | |
| 606 | 1 | 40 | goto on_error; | |
| 607 | - | } | ||
| 608 | - | } | ||
| 609 | - | |||
| 610 | 443 | 43,44 | if (git_treebuilder_write_with_buffer(oid, bld, shared_buf) < 0) | |
| 611 | ##### | 45 | goto on_error; | |
| 612 | - | |||
| 613 | 443 | 46 | git_treebuilder_free(bld); | |
| 614 | 443 | 47 | return (int)i; | |
| 615 | - | |||
| 616 | - | on_error: | ||
| 617 | 17 | 48 | git_treebuilder_free(bld); | |
| 618 | 17 | 49 | return -1; | |
| 619 | - | } | ||
| 620 | - | |||
| 621 | ![]() |
353 | 2 | int git_tree__write_index( |
| 622 | - | git_oid *oid, git_index *index, git_repository *repo) | ||
| 623 | - | { | ||
| 624 | - | int ret; | ||
| 625 | - | git_tree *tree; | ||
| 626 | 353 | 2 | git_buf shared_buf = GIT_BUF_INIT; | |
| 627 | 353 | 2 | bool old_ignore_case = false; | |
| 628 | - | |||
| 629 | 353 | 2-5 | assert(oid && index && repo); | |
| 630 | - | |||
| 631 | 353 | 6,7 | if (git_index_has_conflicts(index)) { | |
| 632 | 1 | 8 | git_error_set(GIT_ERROR_INDEX, | |
| 633 | - | "cannot create a tree from a not fully merged index."); | ||
| 634 | 1 | 9 | return GIT_EUNMERGED; | |
| 635 | - | } | ||
| 636 | - | |||
| 637 | 352 | 10,11 | if (index->tree != NULL && index->tree->entry_count >= 0) { | |
| 638 | 21 | 12 | git_oid_cpy(oid, &index->tree->oid); | |
| 639 | 21 | 13 | return 0; | |
| 640 | - | } | ||
| 641 | - | |||
| 642 | - | /* The tree cache didn't help us; we'll have to write | ||
| 643 | - | * out a tree. If the index is ignore_case, we must | ||
| 644 | - | * make it case-sensitive for the duration of the tree-write | ||
| 645 | - | * operation. */ | ||
| 646 | - | |||
| 647 | 331 | 14 | if (index->ignore_case) { | |
| 648 | 3 | 15 | old_ignore_case = true; | |
| 649 | 3 | 15 | git_index__set_ignore_case(index, false); | |
| 650 | - | } | ||
| 651 | - | |||
| 652 | 331 | 16 | ret = write_tree(oid, repo, index, "", 0, &shared_buf); | |
| 653 | 331 | 17 | git_buf_dispose(&shared_buf); | |
| 654 | - | |||
| 655 | 331 | 18 | if (old_ignore_case) | |
| 656 | 3 | 19 | git_index__set_ignore_case(index, true); | |
| 657 | - | |||
| 658 | 331 | 20 | index->tree = NULL; | |
| 659 | - | |||
| 660 | 331 | 20 | if (ret < 0) | |
| 661 | 15 | 21 | return ret; | |
| 662 | - | |||
| 663 | 316 | 22 | git_pool_clear(&index->tree_pool); | |
| 664 | - | |||
| 665 | 316 | 23,24 | if ((ret = git_tree_lookup(&tree, repo, oid)) < 0) | |
| 666 | ##### | 25 | return ret; | |
| 667 | - | |||
| 668 | - | /* Read the tree cache into the index */ | ||
| 669 | 316 | 26 | ret = git_tree_cache_read_tree(&index->tree, tree, &index->tree_pool); | |
| 670 | 316 | 27 | git_tree_free(tree); | |
| 671 | - | |||
| 672 | 316 | 28 | return ret; | |
| 673 | - | } | ||
| 674 | - | |||
| 675 | ![]() |
620 | 2 | int git_treebuilder_new( |
| 676 | - | git_treebuilder **builder_p, | ||
| 677 | - | git_repository *repo, | ||
| 678 | - | const git_tree *source) | ||
| 679 | - | { | ||
| 680 | - | git_treebuilder *bld; | ||
| 681 | - | size_t i; | ||
| 682 | - | |||
| 683 | 620 | 2-4 | assert(builder_p && repo); | |
| 684 | - | |||
| 685 | 620 | 5 | bld = git__calloc(1, sizeof(git_treebuilder)); | |
| 686 | 620 | 6,7 | GIT_ERROR_CHECK_ALLOC(bld); | |
| 687 | - | |||
| 688 | 620 | 8 | bld->repo = repo; | |
| 689 | - | |||
| 690 | 620 | 8,9 | if (git_strmap_new(&bld->map) < 0) { | |
| 691 | ##### | 10 | git__free(bld); | |
| 692 | ##### | 11 | return -1; | |
| 693 | - | } | ||
| 694 | - | |||
| 695 | 620 | 12 | if (source != NULL) { | |
| 696 | - | git_tree_entry *entry_src; | ||
| 697 | - | |||
| 698 | 237 | 13,17-19 | git_array_foreach(source->entries, i, entry_src) { | |
| 699 | 184 | 14,15 | if (append_entry( | |
| 700 | - | bld, entry_src->filename, | ||
| 701 | - | entry_src->oid, | ||
| 702 | 184 | 14 | entry_src->attr, | |
| 703 | - | false) < 0) | ||
| 704 | ##### | 16 | goto on_error; | |
| 705 | - | } | ||
| 706 | - | } | ||
| 707 | - | |||
| 708 | 620 | 20 | *builder_p = bld; | |
| 709 | 620 | 20 | return 0; | |
| 710 | - | |||
| 711 | - | on_error: | ||
| 712 | ##### | 21 | git_treebuilder_free(bld); | |
| 713 | ##### | 22 | return -1; | |
| 714 | - | } | ||
| 715 | - | |||
| 716 | ![]() |
1275 | 2 | int git_treebuilder_insert( |
| 717 | - | const git_tree_entry **entry_out, | ||
| 718 | - | git_treebuilder *bld, | ||
| 719 | - | const char *filename, | ||
| 720 | - | const git_oid *id, | ||
| 721 | - | git_filemode_t filemode) | ||
| 722 | - | { | ||
| 723 | - | git_tree_entry *entry; | ||
| 724 | - | int error; | ||
| 725 | - | |||
| 726 | 1275 | 2-5 | assert(bld && id && filename); | |
| 727 | - | |||
| 728 | 1275 | 6,7 | if ((error = check_entry(bld->repo, filename, id, filemode)) < 0) | |
| 729 | 24 | 8 | return error; | |
| 730 | - | |||
| 731 | 1251 | 9,10 | if ((entry = git_strmap_get(bld->map, filename)) != NULL) { | |
| 732 | 14 | 11 | git_oid_cpy((git_oid *) entry->oid, id); | |
| 733 | - | } else { | ||
| 734 | 1237 | 12 | entry = alloc_entry(filename, strlen(filename), id); | |
| 735 | 1237 | 13,14 | GIT_ERROR_CHECK_ALLOC(entry); | |
| 736 | - | |||
| 737 | 1237 | 15,16 | if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) { | |
| 738 | ##### | 17 | git_tree_entry_free(entry); | |
| 739 | ##### | 18 | git_error_set(GIT_ERROR_TREE, "failed to insert %s", filename); | |
| 740 | ##### | 19 | return -1; | |
| 741 | - | } | ||
| 742 | - | } | ||
| 743 | - | |||
| 744 | 1251 | 20 | entry->attr = filemode; | |
| 745 | - | |||
| 746 | 1251 | 20 | if (entry_out) | |
| 747 | 62 | 21 | *entry_out = entry; | |
| 748 | - | |||
| 749 | 1251 | 22 | return 0; | |
| 750 | - | } | ||
| 751 | - | |||
| 752 | ![]() |
60 | 2 | static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) |
| 753 | - | { | ||
| 754 | 60 | 2-4 | assert(bld && filename); | |
| 755 | 60 | 5 | return git_strmap_get(bld->map, filename); | |
| 756 | - | } | ||
| 757 | - | |||
| 758 | 23 | 2 | const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) | |
| 759 | - | { | ||
| 760 | 23 | 2 | return treebuilder_get(bld, filename); | |
| 761 | - | } | ||
| 762 | - | |||
| 763 | 15 | 2 | int git_treebuilder_remove(git_treebuilder *bld, const char *filename) | |
| 764 | - | { | ||
| 765 | 15 | 2 | git_tree_entry *entry = treebuilder_get(bld, filename); | |
| 766 | - | |||
| 767 | 15 | 3 | if (entry == NULL) | |
| 768 | ##### | 4 | return tree_error("failed to remove entry: file isn't in the tree", filename); | |
| 769 | - | |||
| 770 | 15 | 5 | git_strmap_delete(bld->map, filename); | |
| 771 | 15 | 6 | git_tree_entry_free(entry); | |
| 772 | - | |||
| 773 | 15 | 7 | return 0; | |
| 774 | - | } | ||
| 775 | - | |||
| 776 | 150 | 2 | int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) | |
| 777 | - | { | ||
| 778 | - | int error; | ||
| 779 | 150 | 2 | git_buf buffer = GIT_BUF_INIT; | |
| 780 | - | |||
| 781 | 150 | 2 | error = git_treebuilder_write_with_buffer(oid, bld, &buffer); | |
| 782 | - | |||
| 783 | 150 | 3 | git_buf_dispose(&buffer); | |
| 784 | 150 | 4 | return error; | |
| 785 | - | } | ||
| 786 | - | |||
| 787 | ![]() |
593 | 2 | int git_treebuilder_write_with_buffer(git_oid *oid, git_treebuilder *bld, git_buf *tree) |
| 788 | - | { | ||
| 789 | 593 | 2 | int error = 0; | |
| 790 | - | size_t i, entrycount; | ||
| 791 | - | git_odb *odb; | ||
| 792 | - | git_tree_entry *entry; | ||
| 793 | 593 | 2 | git_vector entries = GIT_VECTOR_INIT; | |
| 794 | - | |||
| 795 | 593 | 2,3 | assert(bld); | |
| 796 | 593 | 4,5 | assert(tree); | |
| 797 | - | |||
| 798 | 593 | 6 | git_buf_clear(tree); | |
| 799 | - | |||
| 800 | 593 | 7 | entrycount = git_strmap_size(bld->map); | |
| 801 | 593 | 8,9 | if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0) | |
| 802 | ##### | 10 | goto out; | |
| 803 | - | |||
| 804 | 593 | 11-13 | if (tree->asize == 0 && | |
| 805 | 480 | 12 | (error = git_buf_grow(tree, entrycount * 72)) < 0) | |
| 806 | ##### | 14 | goto out; | |
| 807 | - | |||
| 808 | 4527 | 15-20 | git_strmap_foreach_value(bld->map, entry, { | |
| 809 | - | if ((error = git_vector_insert(&entries, entry)) < 0) | ||
| 810 | - | goto out; | ||
| 811 | - | }); | ||
| 812 | - | |||
| 813 | 593 | 21 | git_vector_sort(&entries); | |
| 814 | - | |||
| 815 | 4527 | 22,30-32 | for (i = 0; i < entries.length && !error; ++i) { | |
| 816 | 3934 | 23 | entry = git_vector_get(&entries, i); | |
| 817 | - | |||
| 818 | 3934 | 24 | git_buf_printf(tree, "%o ", entry->attr); | |
| 819 | 3934 | 25 | git_buf_put(tree, entry->filename, entry->filename_len + 1); | |
| 820 | 3934 | 26 | git_buf_put(tree, (char *)entry->oid->id, GIT_OID_RAWSZ); | |
| 821 | - | |||
| 822 | 3934 | 27,28 | if (git_buf_oom(tree)) { | |
| 823 | ##### | 29 | error = -1; | |
| 824 | ##### | 29 | goto out; | |
| 825 | - | } | ||
| 826 | - | } | ||
| 827 | - | |||
| 828 | 593 | 33,34 | if ((error = git_repository_odb__weakptr(&odb, bld->repo)) == 0) | |
| 829 | 593 | 35 | error = git_odb_write(oid, odb, tree->ptr, tree->size, GIT_OBJECT_TREE); | |
| 830 | - | |||
| 831 | - | out: | ||
| 832 | 593 | 36 | git_vector_free(&entries); | |
| 833 | - | |||
| 834 | 593 | 37 | return error; | |
| 835 | - | } | ||
| 836 | - | |||
| 837 | ![]() |
2 | 2 | int git_treebuilder_filter( |
| 838 | - | git_treebuilder *bld, | ||
| 839 | - | git_treebuilder_filter_cb filter, | ||
| 840 | - | void *payload) | ||
| 841 | - | { | ||
| 842 | - | const char *filename; | ||
| 843 | - | git_tree_entry *entry; | ||
| 844 | - | |||
| 845 | 2 | 2-4 | assert(bld && filter); | |
| 846 | - | |||
| 847 | 12 | 5-11 | git_strmap_foreach(bld->map, filename, entry, { | |
| 848 | - | if (filter(entry, payload)) { | ||
| 849 | - | git_strmap_delete(bld->map, filename); | ||
| 850 | - | git_tree_entry_free(entry); | ||
| 851 | - | } | ||
| 852 | - | }); | ||
| 853 | - | |||
| 854 | 2 | 12 | return 0; | |
| 855 | - | } | ||
| 856 | - | |||
| 857 | ![]() |
620 | 2 | int git_treebuilder_clear(git_treebuilder *bld) |
| 858 | - | { | ||
| 859 | - | git_tree_entry *e; | ||
| 860 | - | |||
| 861 | 620 | 2,3 | assert(bld); | |
| 862 | - | |||
| 863 | 3566 | 4-7 | git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e)); | |
| 864 | 620 | 8 | git_strmap_clear(bld->map); | |
| 865 | - | |||
| 866 | 620 | 9 | return 0; | |
| 867 | - | } | ||
| 868 | - | |||
| 869 | 620 | 2 | void git_treebuilder_free(git_treebuilder *bld) | |
| 870 | - | { | ||
| 871 | 620 | 2 | if (bld == NULL) | |
| 872 | 620 | 3,7 | return; | |
| 873 | - | |||
| 874 | 620 | 4 | git_treebuilder_clear(bld); | |
| 875 | 620 | 5 | git_strmap_free(bld->map); | |
| 876 | 620 | 6 | git__free(bld); | |
| 877 | - | } | ||
| 878 | - | |||
| 879 | 7762 | 2 | static size_t subpath_len(const char *path) | |
| 880 | - | { | ||
| 881 | 7762 | 2 | const char *slash_pos = strchr(path, '/'); | |
| 882 | 7762 | 2 | if (slash_pos == NULL) | |
| 883 | 4393 | 3 | return strlen(path); | |
| 884 | - | |||
| 885 | 3369 | 4 | return slash_pos - path; | |
| 886 | - | } | ||
| 887 | - | |||
| 888 | ![]() |
7762 | 2 | int git_tree_entry_bypath( |
| 889 | - | git_tree_entry **entry_out, | ||
| 890 | - | const git_tree *root, | ||
| 891 | - | const char *path) | ||
| 892 | - | { | ||
| 893 | 7762 | 2 | int error = 0; | |
| 894 | - | git_tree *subtree; | ||
| 895 | - | const git_tree_entry *entry; | ||
| 896 | - | size_t filename_len; | ||
| 897 | - | |||
| 898 | - | /* Find how long is the current path component (i.e. | ||
| 899 | - | * the filename between two slashes */ | ||
| 900 | 7762 | 2 | filename_len = subpath_len(path); | |
| 901 | - | |||
| 902 | 7762 | 3 | if (filename_len == 0) { | |
| 903 | 4 | 4 | git_error_set(GIT_ERROR_TREE, "invalid tree path given"); | |
| 904 | 4 | 5 | return GIT_ENOTFOUND; | |
| 905 | - | } | ||
| 906 | - | |||
| 907 | 7758 | 6 | entry = entry_fromname(root, path, filename_len); | |
| 908 | - | |||
| 909 | 7758 | 7 | if (entry == NULL) { | |
| 910 | 187 | 8 | git_error_set(GIT_ERROR_TREE, | |
| 911 | - | "the path '%.*s' does not exist in the given tree", (int) filename_len, path); | ||
| 912 | 187 | 9 | return GIT_ENOTFOUND; | |
| 913 | - | } | ||
| 914 | - | |||
| 915 | 7571 | 10 | switch (path[filename_len]) { | |
| 916 | - | case '/': | ||
| 917 | - | /* If there are more components in the path... | ||
| 918 | - | * then this entry *must* be a tree */ | ||
| 919 | 3347 | 11,12 | if (!git_tree_entry__is_tree(entry)) { | |
| 920 | 3 | 13 | git_error_set(GIT_ERROR_TREE, | |
| 921 | - | "the path '%.*s' exists but is not a tree", (int) filename_len, path); | ||
| 922 | 3 | 14 | return GIT_ENOTFOUND; | |
| 923 | - | } | ||
| 924 | - | |||
| 925 | - | /* If there's only a slash left in the path, we | ||
| 926 | - | * return the current entry; otherwise, we keep | ||
| 927 | - | * walking down the path */ | ||
| 928 | 3344 | 15 | if (path[filename_len + 1] != '\0') | |
| 929 | 3340 | 16 | break; | |
| 930 | - | /* fall through */ | ||
| 931 | - | case '\0': | ||
| 932 | - | /* If there are no more components in the path, return | ||
| 933 | - | * this entry */ | ||
| 934 | 4228 | 17 | return git_tree_entry_dup(entry_out, entry); | |
| 935 | - | } | ||
| 936 | - | |||
| 937 | 3340 | 18,19 | if (git_tree_lookup(&subtree, root->object.repo, entry->oid) < 0) | |
| 938 | ##### | 20 | return -1; | |
| 939 | - | |||
| 940 | 3340 | 21 | error = git_tree_entry_bypath( | |
| 941 | - | entry_out, | ||
| 942 | - | subtree, | ||
| 943 | 3340 | 21 | path + filename_len + 1 | |
| 944 | - | ); | ||
| 945 | - | |||
| 946 | 3340 | 22 | git_tree_free(subtree); | |
| 947 | 3340 | 23 | return error; | |
| 948 | - | } | ||
| 949 | - | |||
| 950 | ![]() |
607 | 2 | static int tree_walk( |
| 951 | - | const git_tree *tree, | ||
| 952 | - | git_treewalk_cb callback, | ||
| 953 | - | git_buf *path, | ||
| 954 | - | void *payload, | ||
| 955 | - | bool preorder) | ||
| 956 | - | { | ||
| 957 | 607 | 2 | int error = 0; | |
| 958 | - | size_t i; | ||
| 959 | - | const git_tree_entry *entry; | ||
| 960 | - | |||
| 961 | 2696 | 2,34-36 | git_array_foreach(tree->entries, i, entry) { | |
| 962 | 2097 | 3 | if (preorder) { | |
| 963 | 540 | 4 | error = callback(path->ptr, entry, payload); | |
| 964 | 540 | 5 | if (error < 0) { /* negative value stops iteration */ | |
| 965 | 4 | 6 | git_error_set_after_callback_function(error, "git_tree_walk"); | |
| 966 | 4 | 7 | break; | |
| 967 | - | } | ||
| 968 | 536 | 8 | if (error > 0) { /* positive value skips this entry */ | |
| 969 | 2 | 9 | error = 0; | |
| 970 | 2 | 9 | continue; | |
| 971 | - | } | ||
| 972 | - | } | ||
| 973 | - | |||
| 974 | 2091 | 10,11 | if (git_tree_entry__is_tree(entry)) { | |
| 975 | - | git_tree *subtree; | ||
| 976 | 82 | 12 | size_t path_len = git_buf_len(path); | |
| 977 | - | |||
| 978 | 82 | 13 | error = git_tree_lookup(&subtree, tree->object.repo, entry->oid); | |
| 979 | 82 | 14 | if (error < 0) | |
| 980 | 2 | 15,27 | break; | |
| 981 | - | |||
| 982 | - | /* append the next entry to the path */ | ||
| 983 | 82 | 16 | git_buf_puts(path, entry->filename); | |
| 984 | 82 | 17 | git_buf_putc(path, '/'); | |
| 985 | - | |||
| 986 | 82 | 18,19 | if (git_buf_oom(path)) | |
| 987 | ##### | 20 | error = -1; | |
| 988 | - | else | ||
| 989 | 82 | 21 | error = tree_walk(subtree, callback, path, payload, preorder); | |
| 990 | - | |||
| 991 | 82 | 22 | git_tree_free(subtree); | |
| 992 | 82 | 23 | if (error != 0) | |
| 993 | 2 | 24 | break; | |
| 994 | - | |||
| 995 | 80 | 25,26 | git_buf_truncate(path, path_len); | |
| 996 | - | } | ||
| 997 | - | |||
| 998 | 2089 | 28 | if (!preorder) { | |
| 999 | 1557 | 29 | error = callback(path->ptr, entry, payload); | |
| 1000 | 1557 | 30 | if (error < 0) { /* negative value stops iteration */ | |
| 1001 | 2 | 31 | git_error_set_after_callback_function(error, "git_tree_walk"); | |
| 1002 | 2 | 32 | break; | |
| 1003 | - | } | ||
| 1004 | 1555 | 33 | error = 0; | |
| 1005 | - | } | ||
| 1006 | - | } | ||
| 1007 | - | |||
| 1008 | 607 | 37 | return error; | |
| 1009 | - | } | ||
| 1010 | - | |||
| 1011 | 525 | 2 | int git_tree_walk( | |
| 1012 | - | const git_tree *tree, | ||
| 1013 | - | git_treewalk_mode mode, | ||
| 1014 | - | git_treewalk_cb callback, | ||
| 1015 | - | void *payload) | ||
| 1016 | - | { | ||
| 1017 | 525 | 2 | int error = 0; | |
| 1018 | 525 | 2 | git_buf root_path = GIT_BUF_INIT; | |
| 1019 | - | |||
| 1020 | 525 | 2,3 | if (mode != GIT_TREEWALK_POST && mode != GIT_TREEWALK_PRE) { | |
| 1021 | ##### | 4 | git_error_set(GIT_ERROR_INVALID, "invalid walking mode for tree walk"); | |
| 1022 | ##### | 5 | return -1; | |
| 1023 | - | } | ||
| 1024 | - | |||
| 1025 | 525 | 6 | error = tree_walk( | |
| 1026 | - | tree, callback, &root_path, payload, (mode == GIT_TREEWALK_PRE)); | ||
| 1027 | - | |||
| 1028 | 525 | 7 | git_buf_dispose(&root_path); | |
| 1029 | - | |||
| 1030 | 525 | 8 | return error; | |
| 1031 | - | } | ||
| 1032 | - | |||
| 1033 | 13 | 2 | static int compare_entries(const void *_a, const void *_b) | |
| 1034 | - | { | ||
| 1035 | 13 | 2 | const git_tree_update *a = (git_tree_update *) _a; | |
| 1036 | 13 | 2 | const git_tree_update *b = (git_tree_update *) _b; | |
| 1037 | - | |||
| 1038 | 13 | 2 | return strcmp(a->path, b->path); | |
| 1039 | - | } | ||
| 1040 | - | |||
| 1041 | 1 | 2 | static int on_dup_entry(void **old, void *new) | |
| 1042 | - | { | ||
| 1043 | - | GIT_UNUSED(old); GIT_UNUSED(new); | ||
| 1044 | - | |||
| 1045 | 1 | 2 | git_error_set(GIT_ERROR_TREE, "duplicate entries given for update"); | |
| 1046 | 1 | 3 | return -1; | |
| 1047 | - | } | ||
| 1048 | - | |||
| 1049 | - | /* | ||
| 1050 | - | * We keep the previous tree and the new one at each level of the | ||
| 1051 | - | * stack. When we leave a level we're done with that tree and we can | ||
| 1052 | - | * write it out to the odb. | ||
| 1053 | - | */ | ||
| 1054 | - | typedef struct { | ||
| 1055 | - | git_treebuilder *bld; | ||
| 1056 | - | git_tree *tree; | ||
| 1057 | - | char *name; | ||
| 1058 | - | } tree_stack_entry; | ||
| 1059 | - | |||
| 1060 | - | /** Count how many slashes (i.e. path components) there are in this string */ | ||
| 1061 | 10 | 2 | GIT_INLINE(size_t) count_slashes(const char *path) | |
| 1062 | - | { | ||
| 1063 | 10 | 2 | size_t count = 0; | |
| 1064 | - | const char *slash; | ||
| 1065 | - | |||
| 1066 | 22 | 2,4 | while ((slash = strchr(path, '/')) != NULL) { | |
| 1067 | 12 | 3 | count++; | |
| 1068 | 12 | 3 | path = slash + 1; | |
| 1069 | - | } | ||
| 1070 | - | |||
| 1071 | 10 | 5 | return count; | |
| 1072 | - | } | ||
| 1073 | - | |||
| 1074 | 44 | 2 | static bool next_component(git_buf *out, const char *in) | |
| 1075 | - | { | ||
| 1076 | 44 | 2 | const char *slash = strchr(in, '/'); | |
| 1077 | - | |||
| 1078 | 44 | 2 | git_buf_clear(out); | |
| 1079 | - | |||
| 1080 | 44 | 3 | if (slash) | |
| 1081 | 25 | 4 | git_buf_put(out, in, slash - in); | |
| 1082 | - | |||
| 1083 | 44 | 5 | return !!slash; | |
| 1084 | - | } | ||
| 1085 | - | |||
| 1086 | ![]() |
23 | 2 | static int create_popped_tree(tree_stack_entry *current, tree_stack_entry *popped, git_buf *component) |
| 1087 | - | { | ||
| 1088 | - | int error; | ||
| 1089 | - | git_oid new_tree; | ||
| 1090 | - | |||
| 1091 | 23 | 2 | git_tree_free(popped->tree); | |
| 1092 | - | |||
| 1093 | - | /* If the tree would be empty, remove it from the one higher up */ | ||
| 1094 | 23 | 3,4 | if (git_treebuilder_entrycount(popped->bld) == 0) { | |
| 1095 | 1 | 5 | git_treebuilder_free(popped->bld); | |
| 1096 | 1 | 6 | error = git_treebuilder_remove(current->bld, popped->name); | |
| 1097 | 1 | 7 | git__free(popped->name); | |
| 1098 | 1 | 8 | return error; | |
| 1099 | - | } | ||
| 1100 | - | |||
| 1101 | 22 | 9 | error = git_treebuilder_write(&new_tree, popped->bld); | |
| 1102 | 22 | 10 | git_treebuilder_free(popped->bld); | |
| 1103 | - | |||
| 1104 | 22 | 11 | if (error < 0) { | |
| 1105 | ##### | 12 | git__free(popped->name); | |
| 1106 | ##### | 13 | return error; | |
| 1107 | - | } | ||
| 1108 | - | |||
| 1109 | - | /* We've written out the tree, now we have to put the new value into its parent */ | ||
| 1110 | 22 | 14 | git_buf_clear(component); | |
| 1111 | 22 | 15 | git_buf_puts(component, popped->name); | |
| 1112 | 22 | 16 | git__free(popped->name); | |
| 1113 | - | |||
| 1114 | 22 | 17,18 | GIT_ERROR_CHECK_ALLOC(component->ptr); | |
| 1115 | - | |||
| 1116 | - | /* Error out if this would create a D/F conflict in this update */ | ||
| 1117 | 22 | 19 | if (current->tree) { | |
| 1118 | - | const git_tree_entry *to_replace; | ||
| 1119 | 6 | 20 | to_replace = git_tree_entry_byname(current->tree, component->ptr); | |
| 1120 | 6 | 21-23 | if (to_replace && git_tree_entry_type(to_replace) != GIT_OBJECT_TREE) { | |
| 1121 | ##### | 24 | git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); | |
| 1122 | ##### | 25 | return -1; | |
| 1123 | - | } | ||
| 1124 | - | } | ||
| 1125 | - | |||
| 1126 | 22 | 26 | return git_treebuilder_insert(NULL, current->bld, component->ptr, &new_tree, GIT_FILEMODE_TREE); | |
| 1127 | - | } | ||
| 1128 | - | |||
| 1129 | ![]() |
12 | 2 | int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates) |
| 1130 | - | { | ||
| 1131 | 12 | 2 | git_array_t(tree_stack_entry) stack = GIT_ARRAY_INIT; | |
| 1132 | - | tree_stack_entry *root_elem; | ||
| 1133 | - | git_vector entries; | ||
| 1134 | - | int error; | ||
| 1135 | - | size_t i; | ||
| 1136 | 12 | 2 | git_buf component = GIT_BUF_INIT; | |
| 1137 | - | |||
| 1138 | 12 | 2,3 | if ((error = git_vector_init(&entries, nupdates, compare_entries)) < 0) | |
| 1139 | ##### | 4 | return error; | |
| 1140 | - | |||
| 1141 | - | /* Sort the entries for treversal */ | ||
| 1142 | 33 | 5,9,10 | for (i = 0 ; i < nupdates; i++) { | |
| 1143 | 22 | 6,7 | if ((error = git_vector_insert_sorted(&entries, (void *) &updates[i], on_dup_entry)) < 0) | |
| 1144 | 1 | 8 | goto cleanup; | |
| 1145 | - | } | ||
| 1146 | - | |||
| 1147 | 11 | 11-16 | root_elem = git_array_alloc(stack); | |
| 1148 | 11 | 17,18 | GIT_ERROR_CHECK_ALLOC(root_elem); | |
| 1149 | 11 | 19 | memset(root_elem, 0, sizeof(*root_elem)); | |
| 1150 | - | |||
| 1151 | 11 | 19-21 | if (baseline && (error = git_tree_dup(&root_elem->tree, baseline)) < 0) | |
| 1152 | ##### | 22 | goto cleanup; | |
| 1153 | - | |||
| 1154 | 11 | 23,24 | if ((error = git_treebuilder_new(&root_elem->bld, repo, root_elem->tree)) < 0) | |
| 1155 | ##### | 25 | goto cleanup; | |
| 1156 | - | |||
| 1157 | 30 | 26,119,120 | for (i = 0; i < nupdates; i++) { | |
| 1158 | 20 | 27-29 | const git_tree_update *last_update = i == 0 ? NULL : git_vector_get(&entries, i-1); | |
| 1159 | 20 | 30 | const git_tree_update *update = git_vector_get(&entries, i); | |
| 1160 | 20 | 31 | size_t common_prefix = 0, steps_up, j; | |
| 1161 | - | const char *path; | ||
| 1162 | - | |||
| 1163 | - | /* Figure out how much we need to change from the previous tree */ | ||
| 1164 | 20 | 31 | if (last_update) | |
| 1165 | 10 | 32 | common_prefix = git_path_common_dirlen(last_update->path, update->path); | |
| 1166 | - | |||
| 1167 | - | /* | ||
| 1168 | - | * The entries are sorted, so when we find we're no | ||
| 1169 | - | * longer in the same directory, we need to abandon | ||
| 1170 | - | * the old tree (steps up) and dive down to the next | ||
| 1171 | - | * one. | ||
| 1172 | - | */ | ||
| 1173 | 20 | 33-35 | steps_up = last_update == NULL ? 0 : count_slashes(&last_update->path[common_prefix]); | |
| 1174 | - | |||
| 1175 | 32 | 36,50,51 | for (j = 0; j < steps_up; j++) { | |
| 1176 | 12 | 37-39 | tree_stack_entry *current, *popped = git_array_pop(stack); | |
| 1177 | 12 | 40,41 | assert(popped); | |
| 1178 | - | |||
| 1179 | 12 | 42-44 | current = git_array_last(stack); | |
| 1180 | 12 | 45,46 | assert(current); | |
| 1181 | - | |||
| 1182 | 12 | 47,48 | if ((error = create_popped_tree(current, popped, &component)) < 0) | |
| 1183 | ##### | 49 | goto cleanup; | |
| 1184 | - | } | ||
| 1185 | - | |||
| 1186 | - | /* Now that we've created the trees we popped from the stack, let's go back down */ | ||
| 1187 | 20 | 52 | path = &update->path[common_prefix]; | |
| 1188 | 44 | 52,86,87 | while (next_component(&component, path)) { | |
| 1189 | - | tree_stack_entry *last, *new_entry; | ||
| 1190 | - | const git_tree_entry *entry; | ||
| 1191 | - | |||
| 1192 | 25 | 53-55 | last = git_array_last(stack); | |
| 1193 | 25 | 56-58 | entry = last->tree ? git_tree_entry_byname(last->tree, component.ptr) : NULL; | |
| 1194 | 25 | 59 | if (!entry) | |
| 1195 | 22 | 60 | entry = treebuilder_get(last->bld, component.ptr); | |
| 1196 | - | |||
| 1197 | 25 | 61-63 | if (entry && git_tree_entry_type(entry) != GIT_OBJECT_TREE) { | |
| 1198 | 1 | 64 | git_error_set(GIT_ERROR_TREE, "D/F conflict when updating tree"); | |
| 1199 | 1 | 65 | error = -1; | |
| 1200 | 1 | 65 | goto cleanup; | |
| 1201 | - | } | ||
| 1202 | - | |||
| 1203 | 24 | 66-71 | new_entry = git_array_alloc(stack); | |
| 1204 | 24 | 72,73 | GIT_ERROR_CHECK_ALLOC(new_entry); | |
| 1205 | 24 | 74 | memset(new_entry, 0, sizeof(*new_entry)); | |
| 1206 | - | |||
| 1207 | 24 | 74 | new_entry->tree = NULL; | |
| 1208 | 24 | 74-77 | if (entry && (error = git_tree_lookup(&new_entry->tree, repo, git_tree_entry_id(entry))) < 0) | |
| 1209 | ##### | 78 | goto cleanup; | |
| 1210 | - | |||
| 1211 | 24 | 79,80 | if ((error = git_treebuilder_new(&new_entry->bld, repo, new_entry->tree)) < 0) | |
| 1212 | ##### | 81 | goto cleanup; | |
| 1213 | - | |||
| 1214 | 24 | 82 | new_entry->name = git__strdup(component.ptr); | |
| 1215 | 24 | 83,84 | GIT_ERROR_CHECK_ALLOC(new_entry->name); | |
| 1216 | - | |||
| 1217 | - | /* Get to the start of the next component */ | ||
| 1218 | 24 | 85 | path += component.size + 1; | |
| 1219 | - | } | ||
| 1220 | - | |||
| 1221 | - | /* After all that, we're finally at the place where we want to perform the update */ | ||
| 1222 | 19 | 88 | switch (update->action) { | |
| 1223 | - | case GIT_TREE_UPDATE_UPSERT: | ||
| 1224 | - | { | ||
| 1225 | - | /* Make sure we're replacing something of the same type */ | ||
| 1226 | 14 | 89-91 | tree_stack_entry *last = git_array_last(stack); | |
| 1227 | 14 | 92 | char *basename = git_path_basename(update->path); | |
| 1228 | 14 | 93 | const git_tree_entry *e = git_treebuilder_get(last->bld, basename); | |
| 1229 | 14 | 94-97 | if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) { | |
| 1230 | ##### | 98 | git__free(basename); | |
| 1231 | ##### | 99-103 | git_error_set(GIT_ERROR_TREE, "cannot replace '%s' with '%s' at '%s'", | |
| 1232 | - | git_object_type2string(git_tree_entry_type(e)), | ||
| 1233 | - | git_object_type2string(git_object__type_from_filemode(update->filemode)), | ||
| 1234 | - | update->path); | ||
| 1235 | ##### | 104 | error = -1; | |
| 1236 | ##### | 104 | goto cleanup; | |
| 1237 | - | } | ||
| 1238 | - | |||
| 1239 | 14 | 105 | error = git_treebuilder_insert(NULL, last->bld, basename, &update->id, update->filemode); | |
| 1240 | 14 | 106 | git__free(basename); | |
| 1241 | 14 | 116 | break; | |
| 1242 | - | } | ||
| 1243 | - | case GIT_TREE_UPDATE_REMOVE: | ||
| 1244 | - | { | ||
| 1245 | 5 | 107 | char *basename = git_path_basename(update->path); | |
| 1246 | 5 | 108-111 | error = git_treebuilder_remove(git_array_last(stack)->bld, basename); | |
| 1247 | 5 | 112 | git__free(basename); | |
| 1248 | 5 | 113 | break; | |
| 1249 | - | } | ||
| 1250 | - | default: | ||
| 1251 | ##### | 114 | git_error_set(GIT_ERROR_TREE, "unknown action for update"); | |
| 1252 | ##### | 115 | error = -1; | |
| 1253 | ##### | 115 | goto cleanup; | |
| 1254 | - | } | ||
| 1255 | - | |||
| 1256 | 19 | 117 | if (error < 0) | |
| 1257 | ##### | 118 | goto cleanup; | |
| 1258 | - | } | ||
| 1259 | - | |||
| 1260 | - | /* We're done, go up the stack again and write out the tree */ | ||
| 1261 | - | { | ||
| 1262 | 10 | 121 | tree_stack_entry *current = NULL, *popped = NULL; | |
| 1263 | 21 | 121,130-133 | while ((popped = git_array_pop(stack)) != NULL) { | |
| 1264 | 21 | 122-124 | current = git_array_last(stack); | |
| 1265 | - | /* We've reached the top, current is the root tree */ | ||
| 1266 | 21 | 125 | if (!current) | |
| 1267 | 10 | 126 | break; | |
| 1268 | - | |||
| 1269 | 11 | 127,128 | if ((error = create_popped_tree(current, popped, &component)) < 0) | |
| 1270 | ##### | 129 | goto cleanup; | |
| 1271 | - | } | ||
| 1272 | - | |||
| 1273 | - | /* Write out the root tree */ | ||
| 1274 | 10 | 134 | git__free(popped->name); | |
| 1275 | 10 | 135 | git_tree_free(popped->tree); | |
| 1276 | - | |||
| 1277 | 10 | 136 | error = git_treebuilder_write(out, popped->bld); | |
| 1278 | 10 | 137 | git_treebuilder_free(popped->bld); | |
| 1279 | 10 | 138 | if (error < 0) | |
| 1280 | ##### | 139 | goto cleanup; | |
| 1281 | - | } | ||
| 1282 | - | |||
| 1283 | - | cleanup: | ||
| 1284 | - | { | ||
| 1285 | - | tree_stack_entry *e; | ||
| 1286 | 14 | 140,144-147 | while ((e = git_array_pop(stack)) != NULL) { | |
| 1287 | 2 | 141 | git_treebuilder_free(e->bld); | |
| 1288 | 2 | 142 | git_tree_free(e->tree); | |
| 1289 | 2 | 143 | git__free(e->name); | |
| 1290 | - | } | ||
| 1291 | - | } | ||
| 1292 | - | |||
| 1293 | 12 | 148 | git_buf_dispose(&component); | |
| 1294 | 12 | 149 | git_array_clear(stack); | |
| 1295 | 12 | 150 | git_vector_free(&entries); | |
| 1296 | 12 | 151 | return error; | |
| 1297 | - | } |