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 "refs.h" 9 #include "hash.h" 10 #include "repository.h" 11 #include "futils.h" 12 #include "filebuf.h" 13 #include "pack.h" 14 #include "parse.h" 15 #include "reflog.h" 16 #include "refdb.h" 17 #include "iterator.h" 18 #include "sortedcache.h" 19 #include "signature.h" 20 #include "wildmatch.h" 21 22 #include <git2/tag.h> 23 #include <git2/object.h> 24 #include <git2/refdb.h> 25 #include <git2/branch.h> 26 #include <git2/sys/refdb_backend.h> 27 #include <git2/sys/refs.h> 28 #include <git2/sys/reflog.h> 29 30 #define DEFAULT_NESTING_LEVEL 5 31 #define MAX_NESTING_LEVEL 10 32 33 enum { 34 PACKREF_HAS_PEEL = 1, 35 PACKREF_WAS_LOOSE = 2, 36 PACKREF_CANNOT_PEEL = 4, 37 PACKREF_SHADOWED = 8, 38 }; 39 40 enum { 41 PEELING_NONE = 0, 42 PEELING_STANDARD, 43 PEELING_FULL 44 }; 45 46 struct packref { 47 git_oid oid; 48 git_oid peel; 49 char flags; 50 char name[GIT_FLEX_ARRAY]; 51 }; 52 53 typedef struct refdb_fs_backend { 54 git_refdb_backend parent; 55 56 git_repository *repo; 57 /* path to git directory */ 58 char *gitpath; 59 /* path to common objects' directory */ 60 char *commonpath; 61 62 git_sortedcache *refcache; 63 int peeling_mode; 64 git_iterator_flag_t iterator_flags; 65 uint32_t direach_flags; 66 int fsync; 67 } refdb_fs_backend; 68 69 static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name); 70 71 static int packref_cmp(const void *a_, const void *b_) 72 { 73 const struct packref *a = a_, *b = b_; 74 return strcmp(a->name, b->name); 75 } 76 77 static int packed_reload(refdb_fs_backend *backend) 78 { 79 int error; 80 git_buf packedrefs = GIT_BUF_INIT; 81 char *scan, *eof, *eol; 82 83 if (!backend->gitpath) 84 return 0; 85 86 error = git_sortedcache_lockandload(backend->refcache, &packedrefs); 87 88 /* 89 * If we can't find the packed-refs, clear table and return. 90 * Any other error just gets passed through. 91 * If no error, and file wasn't changed, just return. 92 * Anything else means we need to refresh the packed refs. 93 */ 94 if (error <= 0) { 95 if (error == GIT_ENOTFOUND) { 96 git_sortedcache_clear(backend->refcache, true); 97 git_error_clear(); 98 error = 0; 99 } 100 return error; 101 } 102 103 /* At this point, refresh the packed refs from the loaded buffer. */ 104 105 git_sortedcache_clear(backend->refcache, false); 106 107 scan = (char *)packedrefs.ptr; 108 eof = scan + packedrefs.size; 109 110 backend->peeling_mode = PEELING_NONE; 111 112 if (*scan == '#') { 113 static const char *traits_header = "# pack-refs with: "; 114 115 if (git__prefixcmp(scan, traits_header) == 0) { 116 scan += strlen(traits_header); 117 eol = strchr(scan, '\n'); 118 119 if (!eol) 120 goto parse_failed; 121 *eol = '\0'; 122 123 if (strstr(scan, " fully-peeled ") != NULL) { 124 backend->peeling_mode = PEELING_FULL; 125 } else if (strstr(scan, " peeled ") != NULL) { 126 backend->peeling_mode = PEELING_STANDARD; 127 } 128 129 scan = eol + 1; 130 } 131 } 132 133 while (scan < eof && *scan == '#') { 134 if (!(eol = strchr(scan, '\n'))) 135 goto parse_failed; 136 scan = eol + 1; 137 } 138 139 while (scan < eof) { 140 struct packref *ref; 141 git_oid oid; 142 143 /* parse "<OID> <refname>\n" */ 144 145 if (git_oid_fromstr(&oid, scan) < 0) 146 goto parse_failed; 147 scan += GIT_OID_HEXSZ; 148 149 if (*scan++ != ' ') 150 goto parse_failed; 151 if (!(eol = strchr(scan, '\n'))) 152 goto parse_failed; 153 *eol = '\0'; 154 if (eol[-1] == '\r') 155 eol[-1] = '\0'; 156 157 if (git_sortedcache_upsert((void **)&ref, backend->refcache, scan) < 0) 158 goto parse_failed; 159 scan = eol + 1; 160 161 git_oid_cpy(&ref->oid, &oid); 162 163 /* look for optional "^<OID>\n" */ 164 165 if (*scan == '^') { 166 if (git_oid_fromstr(&oid, scan + 1) < 0) 167 goto parse_failed; 168 scan += GIT_OID_HEXSZ + 1; 169 170 if (scan < eof) { 171 if (!(eol = strchr(scan, '\n'))) 172 goto parse_failed; 173 scan = eol + 1; 174 } 175 176 git_oid_cpy(&ref->peel, &oid); 177 ref->flags |= PACKREF_HAS_PEEL; 178 } 179 else if (backend->peeling_mode == PEELING_FULL || 180 (backend->peeling_mode == PEELING_STANDARD && 181 git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0)) 182 ref->flags |= PACKREF_CANNOT_PEEL; 183 } 184 185 git_sortedcache_wunlock(backend->refcache); 186 git_buf_dispose(&packedrefs); 187 188 return 0; 189 190 parse_failed: 191 git_error_set(GIT_ERROR_REFERENCE, "corrupted packed references file"); 192 193 git_sortedcache_clear(backend->refcache, false); 194 git_sortedcache_wunlock(backend->refcache); 195 git_buf_dispose(&packedrefs); 196 197 return -1; 198 } 199 200 static int loose_parse_oid( 201 git_oid *oid, const char *filename, git_buf *file_content) 202 { 203 const char *str = git_buf_cstr(file_content); 204 205 if (git_buf_len(file_content) < GIT_OID_HEXSZ) 206 goto corrupted; 207 208 /* we need to get 40 OID characters from the file */ 209 if (git_oid_fromstr(oid, str) < 0) 210 goto corrupted; 211 212 /* If the file is longer than 40 chars, the 41st must be a space */ 213 str += GIT_OID_HEXSZ; 214 if (*str == '\0' || git__isspace(*str)) 215 return 0; 216 217 corrupted: 218 git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file: %s", filename); 219 return -1; 220 } 221 222 static int loose_readbuffer(git_buf *buf, const char *base, const char *path) 223 { 224 int error; 225 226 /* build full path to file */ 227 if ((error = git_buf_joinpath(buf, base, path)) < 0 || 228 (error = git_futils_readbuffer(buf, buf->ptr)) < 0) 229 git_buf_dispose(buf); 230 231 return error; 232 } 233 234 static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name) 235 { 236 int error = 0; 237 git_buf ref_file = GIT_BUF_INIT; 238 struct packref *ref = NULL; 239 git_oid oid; 240 241 /* if we fail to load the loose reference, assume someone changed 242 * the filesystem under us and skip it... 243 */ 244 if (loose_readbuffer(&ref_file, backend->gitpath, name) < 0) { 245 git_error_clear(); 246 goto done; 247 } 248 249 /* skip symbolic refs */ 250 if (!git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF)) 251 goto done; 252 253 /* parse OID from file */ 254 if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0) 255 goto done; 256 257 git_sortedcache_wlock(backend->refcache); 258 259 if (!(error = git_sortedcache_upsert( 260 (void **)&ref, backend->refcache, name))) { 261 262 git_oid_cpy(&ref->oid, &oid); 263 ref->flags = PACKREF_WAS_LOOSE; 264 } 265 266 git_sortedcache_wunlock(backend->refcache); 267 268 done: 269 git_buf_dispose(&ref_file); 270 return error; 271 } 272 273 static int _dirent_loose_load(void *payload, git_buf *full_path) 274 { 275 refdb_fs_backend *backend = payload; 276 const char *file_path; 277 278 if (git__suffixcmp(full_path->ptr, ".lock") == 0) 279 return 0; 280 281 if (git_path_isdir(full_path->ptr)) { 282 int error = git_path_direach( 283 full_path, backend->direach_flags, _dirent_loose_load, backend); 284 /* Race with the filesystem, ignore it */ 285 if (error == GIT_ENOTFOUND) { 286 git_error_clear(); 287 return 0; 288 } 289 290 return error; 291 } 292 293 file_path = full_path->ptr + strlen(backend->gitpath); 294 295 return loose_lookup_to_packfile(backend, file_path); 296 } 297 298 /* 299 * Load all the loose references from the repository 300 * into the in-memory Packfile, and build a vector with 301 * all the references so it can be written back to 302 * disk. 303 */ 304 static int packed_loadloose(refdb_fs_backend *backend) 305 { 306 int error; 307 git_buf refs_path = GIT_BUF_INIT; 308 309 if (git_buf_joinpath(&refs_path, backend->gitpath, GIT_REFS_DIR) < 0) 310 return -1; 311 312 /* 313 * Load all the loose files from disk into the Packfile table. 314 * This will overwrite any old packed entries with their 315 * updated loose versions 316 */ 317 error = git_path_direach( 318 &refs_path, backend->direach_flags, _dirent_loose_load, backend); 319 320 git_buf_dispose(&refs_path); 321 322 return error; 323 } 324 325 static int refdb_fs_backend__exists( 326 int *exists, 327 git_refdb_backend *_backend, 328 const char *ref_name) 329 { 330 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 331 git_buf ref_path = GIT_BUF_INIT; 332 int error; 333 334 GIT_ASSERT_ARG(backend); 335 336 *exists = 0; 337 338 if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0) 339 goto out; 340 341 if (git_path_isfile(ref_path.ptr)) { 342 *exists = 1; 343 goto out; 344 } 345 346 if ((error = packed_reload(backend)) < 0) 347 goto out; 348 349 if (git_sortedcache_lookup(backend->refcache, ref_name) != NULL) { 350 *exists = 1; 351 goto out; 352 } 353 354 out: 355 git_buf_dispose(&ref_path); 356 return error; 357 } 358 359 static const char *loose_parse_symbolic(git_buf *file_content) 360 { 361 const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF); 362 const char *refname_start; 363 364 refname_start = (const char *)file_content->ptr; 365 366 if (git_buf_len(file_content) < header_len + 1) { 367 git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file"); 368 return NULL; 369 } 370 371 /* 372 * Assume we have already checked for the header 373 * before calling this function 374 */ 375 refname_start += header_len; 376 377 return refname_start; 378 } 379 380 /* 381 * Returns whether a reference is stored per worktree or not. 382 * Per-worktree references are: 383 * 384 * - all pseudorefs, e.g. HEAD and MERGE_HEAD 385 * - all references stored inside of "refs/bisect/" 386 */ 387 static bool is_per_worktree_ref(const char *ref_name) 388 { 389 return git__prefixcmp(ref_name, "refs/") != 0 || 390 git__prefixcmp(ref_name, "refs/bisect/") == 0; 391 } 392 393 static int loose_lookup( 394 git_reference **out, 395 refdb_fs_backend *backend, 396 const char *ref_name) 397 { 398 git_buf ref_file = GIT_BUF_INIT; 399 int error = 0; 400 const char *ref_dir; 401 402 if (out) 403 *out = NULL; 404 405 if (is_per_worktree_ref(ref_name)) 406 ref_dir = backend->gitpath; 407 else 408 ref_dir = backend->commonpath; 409 410 if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0) 411 /* cannot read loose ref file - gah */; 412 else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) { 413 const char *target; 414 415 git_buf_rtrim(&ref_file); 416 417 if (!(target = loose_parse_symbolic(&ref_file))) 418 error = -1; 419 else if (out != NULL) 420 *out = git_reference__alloc_symbolic(ref_name, target); 421 } else { 422 git_oid oid; 423 424 if (!(error = loose_parse_oid(&oid, ref_name, &ref_file)) && 425 out != NULL) 426 *out = git_reference__alloc(ref_name, &oid, NULL); 427 } 428 429 git_buf_dispose(&ref_file); 430 return error; 431 } 432 433 static int ref_error_notfound(const char *name) 434 { 435 git_error_set(GIT_ERROR_REFERENCE, "reference '%s' not found", name); 436 return GIT_ENOTFOUND; 437 } 438 439 static int packed_lookup( 440 git_reference **out, 441 refdb_fs_backend *backend, 442 const char *ref_name) 443 { 444 int error = 0; 445 struct packref *entry; 446 447 if ((error = packed_reload(backend)) < 0) 448 return error; 449 450 if (git_sortedcache_rlock(backend->refcache) < 0) 451 return -1; 452 453 entry = git_sortedcache_lookup(backend->refcache, ref_name); 454 if (!entry) { 455 error = ref_error_notfound(ref_name); 456 } else { 457 *out = git_reference__alloc(ref_name, &entry->oid, &entry->peel); 458 if (!*out) 459 error = -1; 460 } 461 462 git_sortedcache_runlock(backend->refcache); 463 464 return error; 465 } 466 467 static int refdb_fs_backend__lookup( 468 git_reference **out, 469 git_refdb_backend *_backend, 470 const char *ref_name) 471 { 472 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 473 int error; 474 475 GIT_ASSERT_ARG(backend); 476 477 if (!(error = loose_lookup(out, backend, ref_name))) 478 return 0; 479 480 /* only try to lookup this reference on the packfile if it 481 * wasn't found on the loose refs; not if there was a critical error */ 482 if (error == GIT_ENOTFOUND) { 483 git_error_clear(); 484 error = packed_lookup(out, backend, ref_name); 485 } 486 487 return error; 488 } 489 490 typedef struct { 491 git_reference_iterator parent; 492 493 char *glob; 494 495 git_pool pool; 496 git_vector loose; 497 498 git_sortedcache *cache; 499 size_t loose_pos; 500 size_t packed_pos; 501 } refdb_fs_iter; 502 503 static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter) 504 { 505 refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent); 506 507 git_vector_free(&iter->loose); 508 git_pool_clear(&iter->pool); 509 git_sortedcache_free(iter->cache); 510 git__free(iter); 511 } 512 513 static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter) 514 { 515 int error = 0; 516 git_buf path = GIT_BUF_INIT; 517 git_iterator *fsit = NULL; 518 git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT; 519 const git_index_entry *entry = NULL; 520 const char *ref_prefix = GIT_REFS_DIR; 521 size_t ref_prefix_len = strlen(ref_prefix); 522 523 if (!backend->commonpath) /* do nothing if no commonpath for loose refs */ 524 return 0; 525 526 fsit_opts.flags = backend->iterator_flags; 527 528 if (iter->glob) { 529 const char *last_sep = NULL; 530 const char *pos; 531 for (pos = iter->glob; *pos; ++pos) { 532 switch (*pos) { 533 case '?': 534 case '*': 535 case '[': 536 case '\\': 537 break; 538 case '/': 539 last_sep = pos; 540 /* FALLTHROUGH */ 541 default: 542 continue; 543 } 544 break; 545 } 546 if (last_sep) { 547 ref_prefix = iter->glob; 548 ref_prefix_len = (last_sep - ref_prefix) + 1; 549 } 550 } 551 552 if ((error = git_buf_printf(&path, "%s/", backend->commonpath)) < 0 || 553 (error = git_buf_put(&path, ref_prefix, ref_prefix_len)) < 0) { 554 git_buf_dispose(&path); 555 return error; 556 } 557 558 if ((error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) { 559 git_buf_dispose(&path); 560 return (iter->glob && error == GIT_ENOTFOUND)? 0 : error; 561 } 562 563 error = git_buf_sets(&path, ref_prefix); 564 565 while (!error && !git_iterator_advance(&entry, fsit)) { 566 const char *ref_name; 567 char *ref_dup; 568 569 git_buf_truncate(&path, ref_prefix_len); 570 git_buf_puts(&path, entry->path); 571 ref_name = git_buf_cstr(&path); 572 573 if (git__suffixcmp(ref_name, ".lock") == 0 || 574 (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0)) 575 continue; 576 577 ref_dup = git_pool_strdup(&iter->pool, ref_name); 578 if (!ref_dup) 579 error = -1; 580 else 581 error = git_vector_insert(&iter->loose, ref_dup); 582 } 583 584 git_iterator_free(fsit); 585 git_buf_dispose(&path); 586 587 return error; 588 } 589 590 static int refdb_fs_backend__iterator_next( 591 git_reference **out, git_reference_iterator *_iter) 592 { 593 int error = GIT_ITEROVER; 594 refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent); 595 refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent); 596 struct packref *ref; 597 598 while (iter->loose_pos < iter->loose.length) { 599 const char *path = git_vector_get(&iter->loose, iter->loose_pos++); 600 601 if (loose_lookup(out, backend, path) == 0) { 602 ref = git_sortedcache_lookup(iter->cache, path); 603 if (ref) 604 ref->flags |= PACKREF_SHADOWED; 605 606 return 0; 607 } 608 609 git_error_clear(); 610 } 611 612 error = GIT_ITEROVER; 613 while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) { 614 ref = git_sortedcache_entry(iter->cache, iter->packed_pos++); 615 if (!ref) /* stop now if another thread deleted refs and we past end */ 616 break; 617 618 if (ref->flags & PACKREF_SHADOWED) 619 continue; 620 if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0) 621 continue; 622 623 *out = git_reference__alloc(ref->name, &ref->oid, &ref->peel); 624 error = (*out != NULL) ? 0 : -1; 625 break; 626 } 627 628 return error; 629 } 630 631 static int refdb_fs_backend__iterator_next_name( 632 const char **out, git_reference_iterator *_iter) 633 { 634 int error = GIT_ITEROVER; 635 refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent); 636 refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent); 637 struct packref *ref; 638 639 while (iter->loose_pos < iter->loose.length) { 640 const char *path = git_vector_get(&iter->loose, iter->loose_pos++); 641 struct packref *ref; 642 643 if (loose_lookup(NULL, backend, path) == 0) { 644 ref = git_sortedcache_lookup(iter->cache, path); 645 if (ref) 646 ref->flags |= PACKREF_SHADOWED; 647 648 *out = path; 649 return 0; 650 } 651 652 git_error_clear(); 653 } 654 655 error = GIT_ITEROVER; 656 while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) { 657 ref = git_sortedcache_entry(iter->cache, iter->packed_pos++); 658 if (!ref) /* stop now if another thread deleted refs and we past end */ 659 break; 660 661 if (ref->flags & PACKREF_SHADOWED) 662 continue; 663 if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0) 664 continue; 665 666 *out = ref->name; 667 error = 0; 668 break; 669 } 670 671 return error; 672 } 673 674 static int refdb_fs_backend__iterator( 675 git_reference_iterator **out, git_refdb_backend *_backend, const char *glob) 676 { 677 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 678 refdb_fs_iter *iter = NULL; 679 int error; 680 681 GIT_ASSERT_ARG(backend); 682 683 iter = git__calloc(1, sizeof(refdb_fs_iter)); 684 GIT_ERROR_CHECK_ALLOC(iter); 685 686 if ((error = git_pool_init(&iter->pool, 1)) < 0) 687 goto out; 688 689 if ((error = git_vector_init(&iter->loose, 8, NULL)) < 0) 690 goto out; 691 692 if (glob != NULL && 693 (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL) { 694 error = GIT_ERROR_NOMEMORY; 695 goto out; 696 } 697 698 if ((error = iter_load_loose_paths(backend, iter)) < 0) 699 goto out; 700 701 if ((error = packed_reload(backend)) < 0) 702 goto out; 703 704 if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0) 705 goto out; 706 707 iter->parent.next = refdb_fs_backend__iterator_next; 708 iter->parent.next_name = refdb_fs_backend__iterator_next_name; 709 iter->parent.free = refdb_fs_backend__iterator_free; 710 711 *out = (git_reference_iterator *)iter; 712 out: 713 if (error) 714 refdb_fs_backend__iterator_free((git_reference_iterator *)iter); 715 return error; 716 } 717 718 static bool ref_is_available( 719 const char *old_ref, const char *new_ref, const char *this_ref) 720 { 721 if (old_ref == NULL || strcmp(old_ref, this_ref)) { 722 size_t reflen = strlen(this_ref); 723 size_t newlen = strlen(new_ref); 724 size_t cmplen = reflen < newlen ? reflen : newlen; 725 const char *lead = reflen < newlen ? new_ref : this_ref; 726 727 if (!strncmp(new_ref, this_ref, cmplen) && lead[cmplen] == '/') { 728 return false; 729 } 730 } 731 732 return true; 733 } 734 735 static int reference_path_available( 736 refdb_fs_backend *backend, 737 const char *new_ref, 738 const char* old_ref, 739 int force) 740 { 741 size_t i; 742 int error; 743 744 if ((error = packed_reload(backend)) < 0) 745 return error; 746 747 if (!force) { 748 int exists; 749 750 if ((error = refdb_fs_backend__exists( 751 &exists, (git_refdb_backend *)backend, new_ref)) < 0) { 752 return error; 753 } 754 755 if (exists) { 756 git_error_set(GIT_ERROR_REFERENCE, 757 "failed to write reference '%s': a reference with " 758 "that name already exists.", new_ref); 759 return GIT_EEXISTS; 760 } 761 } 762 763 git_sortedcache_rlock(backend->refcache); 764 765 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) { 766 struct packref *ref = git_sortedcache_entry(backend->refcache, i); 767 768 if (ref && !ref_is_available(old_ref, new_ref, ref->name)) { 769 git_sortedcache_runlock(backend->refcache); 770 git_error_set(GIT_ERROR_REFERENCE, 771 "path to reference '%s' collides with existing one", new_ref); 772 return -1; 773 } 774 } 775 776 git_sortedcache_runlock(backend->refcache); 777 return 0; 778 } 779 780 static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name) 781 { 782 int error, filebuf_flags; 783 git_buf ref_path = GIT_BUF_INIT; 784 const char *basedir; 785 786 GIT_ASSERT_ARG(file); 787 GIT_ASSERT_ARG(backend); 788 GIT_ASSERT_ARG(name); 789 790 if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { 791 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", name); 792 return GIT_EINVALIDSPEC; 793 } 794 795 if (is_per_worktree_ref(name)) 796 basedir = backend->gitpath; 797 else 798 basedir = backend->commonpath; 799 800 /* Remove a possibly existing empty directory hierarchy 801 * which name would collide with the reference name 802 */ 803 if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0) 804 return error; 805 806 if (git_buf_joinpath(&ref_path, basedir, name) < 0) 807 return -1; 808 809 filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS; 810 if (backend->fsync) 811 filebuf_flags |= GIT_FILEBUF_FSYNC; 812 813 error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE); 814 815 if (error == GIT_EDIRECTORY) 816 git_error_set(GIT_ERROR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name); 817 818 git_buf_dispose(&ref_path); 819 return error; 820 } 821 822 static int loose_commit(git_filebuf *file, const git_reference *ref) 823 { 824 GIT_ASSERT_ARG(file); 825 GIT_ASSERT_ARG(ref); 826 827 if (ref->type == GIT_REFERENCE_DIRECT) { 828 char oid[GIT_OID_HEXSZ + 1]; 829 git_oid_nfmt(oid, sizeof(oid), &ref->target.oid); 830 831 git_filebuf_printf(file, "%s\n", oid); 832 } else if (ref->type == GIT_REFERENCE_SYMBOLIC) { 833 git_filebuf_printf(file, GIT_SYMREF "%s\n", ref->target.symbolic); 834 } else { 835 GIT_ASSERT(0); 836 } 837 838 return git_filebuf_commit(file); 839 } 840 841 static int refdb_fs_backend__lock(void **out, git_refdb_backend *_backend, const char *refname) 842 { 843 int error; 844 git_filebuf *lock; 845 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 846 847 lock = git__calloc(1, sizeof(git_filebuf)); 848 GIT_ERROR_CHECK_ALLOC(lock); 849 850 if ((error = loose_lock(lock, backend, refname)) < 0) { 851 git__free(lock); 852 return error; 853 } 854 855 *out = lock; 856 return 0; 857 } 858 859 static int refdb_fs_backend__write_tail( 860 git_refdb_backend *_backend, 861 const git_reference *ref, 862 git_filebuf *file, 863 int update_reflog, 864 const git_oid *old_id, 865 const char *old_target, 866 const git_signature *who, 867 const char *message); 868 869 static int refdb_fs_backend__delete_tail( 870 git_refdb_backend *_backend, 871 git_filebuf *file, 872 const char *ref_name, 873 const git_oid *old_id, 874 const char *old_target); 875 876 static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog, 877 const git_reference *ref, const git_signature *sig, const char *message) 878 { 879 git_filebuf *lock = (git_filebuf *) payload; 880 int error = 0; 881 882 if (success == 2) 883 error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL); 884 else if (success) 885 error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, NULL, NULL, sig, message); 886 else 887 git_filebuf_cleanup(lock); 888 889 git__free(lock); 890 return error; 891 } 892 893 /* 894 * Find out what object this reference resolves to. 895 * 896 * For references that point to a 'big' tag (e.g. an 897 * actual tag object on the repository), we need to 898 * cache on the packfile the OID of the object to 899 * which that 'big tag' is pointing to. 900 */ 901 static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) 902 { 903 git_object *object; 904 905 if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL) 906 return 0; 907 908 /* 909 * Find the tagged object in the repository 910 */ 911 if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJECT_ANY) < 0) 912 return -1; 913 914 /* 915 * If the tagged object is a Tag object, we need to resolve it; 916 * if the ref is actually a 'weak' ref, we don't need to resolve 917 * anything. 918 */ 919 if (git_object_type(object) == GIT_OBJECT_TAG) { 920 git_tag *tag = (git_tag *)object; 921 922 /* 923 * Find the object pointed at by this tag 924 */ 925 git_oid_cpy(&ref->peel, git_tag_target_id(tag)); 926 ref->flags |= PACKREF_HAS_PEEL; 927 928 /* 929 * The reference has now cached the resolved OID, and is 930 * marked at such. When written to the packfile, it'll be 931 * accompanied by this resolved oid 932 */ 933 } 934 935 git_object_free(object); 936 return 0; 937 } 938 939 /* 940 * Write a single reference into a packfile 941 */ 942 static int packed_write_ref(struct packref *ref, git_filebuf *file) 943 { 944 char oid[GIT_OID_HEXSZ + 1]; 945 git_oid_nfmt(oid, sizeof(oid), &ref->oid); 946 947 /* 948 * For references that peel to an object in the repo, we must 949 * write the resulting peel on a separate line, e.g. 950 * 951 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4 952 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100 953 * 954 * This obviously only applies to tags. 955 * The required peels have already been loaded into `ref->peel_target`. 956 */ 957 if (ref->flags & PACKREF_HAS_PEEL) { 958 char peel[GIT_OID_HEXSZ + 1]; 959 git_oid_nfmt(peel, sizeof(peel), &ref->peel); 960 961 if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0) 962 return -1; 963 } else { 964 if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0) 965 return -1; 966 } 967 968 return 0; 969 } 970 971 /* 972 * Remove all loose references 973 * 974 * Once we have successfully written a packfile, 975 * all the loose references that were packed must be 976 * removed from disk. 977 * 978 * This is a dangerous method; make sure the packfile 979 * is well-written, because we are destructing references 980 * here otherwise. 981 */ 982 static int packed_remove_loose(refdb_fs_backend *backend) 983 { 984 size_t i; 985 git_filebuf lock = GIT_FILEBUF_INIT; 986 git_buf ref_content = GIT_BUF_INIT; 987 int error = 0; 988 989 /* backend->refcache is already locked when this is called */ 990 991 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) { 992 struct packref *ref = git_sortedcache_entry(backend->refcache, i); 993 git_oid current_id; 994 995 if (!ref || !(ref->flags & PACKREF_WAS_LOOSE)) 996 continue; 997 998 git_filebuf_cleanup(&lock); 999 1000 /* We need to stop anybody from updating the ref while we try to do a safe delete */ 1001 error = loose_lock(&lock, backend, ref->name); 1002 /* If someone else is updating it, let them do it */ 1003 if (error == GIT_EEXISTS || error == GIT_ENOTFOUND) 1004 continue; 1005 1006 if (error < 0) { 1007 git_buf_dispose(&ref_content); 1008 git_error_set(GIT_ERROR_REFERENCE, "failed to lock loose reference '%s'", ref->name); 1009 return error; 1010 } 1011 1012 error = git_futils_readbuffer(&ref_content, lock.path_original); 1013 /* Someone else beat us to cleaning up the ref, let's simply continue */ 1014 if (error == GIT_ENOTFOUND) 1015 continue; 1016 1017 /* This became a symref between us packing and trying to delete it, so ignore it */ 1018 if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF)) 1019 continue; 1020 1021 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */ 1022 if (loose_parse_oid(¤t_id, lock.path_original, &ref_content) < 0) 1023 continue; 1024 1025 /* If the ref moved since we packed it, we must not delete it */ 1026 if (!git_oid_equal(¤t_id, &ref->oid)) 1027 continue; 1028 1029 /* 1030 * if we fail to remove a single file, this is *not* good, 1031 * but we should keep going and remove as many as possible. 1032 * If we fail to remove, the ref is still in the old state, so 1033 * we haven't lost information. 1034 */ 1035 p_unlink(lock.path_original); 1036 } 1037 1038 git_buf_dispose(&ref_content); 1039 git_filebuf_cleanup(&lock); 1040 return 0; 1041 } 1042 1043 /* 1044 * Write all the contents in the in-memory packfile to disk. 1045 */ 1046 static int packed_write(refdb_fs_backend *backend) 1047 { 1048 git_sortedcache *refcache = backend->refcache; 1049 git_filebuf pack_file = GIT_FILEBUF_INIT; 1050 int error, open_flags = 0; 1051 size_t i; 1052 1053 /* lock the cache to updates while we do this */ 1054 if ((error = git_sortedcache_wlock(refcache)) < 0) 1055 return error; 1056 1057 if (backend->fsync) 1058 open_flags = GIT_FILEBUF_FSYNC; 1059 1060 /* Open the file! */ 1061 if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0) 1062 goto fail; 1063 1064 /* Packfiles have a header... apparently 1065 * This is in fact not required, but we might as well print it 1066 * just for kicks */ 1067 if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0) 1068 goto fail; 1069 1070 for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) { 1071 struct packref *ref = git_sortedcache_entry(refcache, i); 1072 GIT_ASSERT(ref); 1073 1074 if ((error = packed_find_peel(backend, ref)) < 0) 1075 goto fail; 1076 1077 if ((error = packed_write_ref(ref, &pack_file)) < 0) 1078 goto fail; 1079 } 1080 1081 /* if we've written all the references properly, we can commit 1082 * the packfile to make the changes effective */ 1083 if ((error = git_filebuf_commit(&pack_file)) < 0) 1084 goto fail; 1085 1086 /* when and only when the packfile has been properly written, 1087 * we can go ahead and remove the loose refs */ 1088 if ((error = packed_remove_loose(backend)) < 0) 1089 goto fail; 1090 1091 git_sortedcache_updated(refcache); 1092 git_sortedcache_wunlock(refcache); 1093 1094 /* we're good now */ 1095 return 0; 1096 1097 fail: 1098 git_filebuf_cleanup(&pack_file); 1099 git_sortedcache_wunlock(refcache); 1100 1101 return error; 1102 } 1103 1104 static int packed_delete(refdb_fs_backend *backend, const char *ref_name) 1105 { 1106 size_t pack_pos; 1107 int error, found = 0; 1108 1109 if ((error = packed_reload(backend)) < 0) 1110 goto cleanup; 1111 1112 if ((error = git_sortedcache_wlock(backend->refcache)) < 0) 1113 goto cleanup; 1114 1115 /* If a packed reference exists, remove it from the packfile and repack if necessary */ 1116 error = git_sortedcache_lookup_index(&pack_pos, backend->refcache, ref_name); 1117 if (error == 0) { 1118 error = git_sortedcache_remove(backend->refcache, pack_pos); 1119 found = 1; 1120 } 1121 if (error == GIT_ENOTFOUND) 1122 error = 0; 1123 1124 git_sortedcache_wunlock(backend->refcache); 1125 1126 if (found) 1127 error = packed_write(backend); 1128 1129 cleanup: 1130 return error; 1131 } 1132 1133 static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message); 1134 1135 static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name, 1136 const git_oid *old_id, const char *old_target) 1137 { 1138 int error = 0; 1139 git_reference *old_ref = NULL; 1140 1141 *cmp = 0; 1142 /* It "matches" if there is no old value to compare against */ 1143 if (!old_id && !old_target) 1144 return 0; 1145 1146 if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0) 1147 goto out; 1148 1149 /* If the types don't match, there's no way the values do */ 1150 if (old_id && old_ref->type != GIT_REFERENCE_DIRECT) { 1151 *cmp = -1; 1152 goto out; 1153 } 1154 if (old_target && old_ref->type != GIT_REFERENCE_SYMBOLIC) { 1155 *cmp = 1; 1156 goto out; 1157 } 1158 1159 if (old_id && old_ref->type == GIT_REFERENCE_DIRECT) 1160 *cmp = git_oid_cmp(old_id, &old_ref->target.oid); 1161 1162 if (old_target && old_ref->type == GIT_REFERENCE_SYMBOLIC) 1163 *cmp = git__strcmp(old_target, old_ref->target.symbolic); 1164 1165 out: 1166 git_reference_free(old_ref); 1167 1168 return error; 1169 } 1170 1171 /* 1172 * The git.git comment regarding this, for your viewing pleasure: 1173 * 1174 * Special hack: If a branch is updated directly and HEAD 1175 * points to it (may happen on the remote side of a push 1176 * for example) then logically the HEAD reflog should be 1177 * updated too. 1178 * A generic solution implies reverse symref information, 1179 * but finding all symrefs pointing to the given branch 1180 * would be rather costly for this rare event (the direct 1181 * update of a branch) to be worth it. So let's cheat and 1182 * check with HEAD only which should cover 99% of all usage 1183 * scenarios (even 100% of the default ones). 1184 */ 1185 static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message) 1186 { 1187 git_reference *head = NULL; 1188 git_refdb *refdb = NULL; 1189 int error, write_reflog; 1190 git_oid old_id; 1191 1192 if ((error = git_repository_refdb(&refdb, backend->repo)) < 0 || 1193 (error = git_refdb_should_write_head_reflog(&write_reflog, refdb, ref)) < 0) 1194 goto out; 1195 if (!write_reflog) 1196 goto out; 1197 1198 /* if we can't resolve, we use {0}*40 as old id */ 1199 if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0) 1200 memset(&old_id, 0, sizeof(old_id)); 1201 1202 if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0 || 1203 (error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message)) < 0) 1204 goto out; 1205 1206 out: 1207 git_reference_free(head); 1208 git_refdb_free(refdb); 1209 return error; 1210 } 1211 1212 static int refdb_fs_backend__write( 1213 git_refdb_backend *_backend, 1214 const git_reference *ref, 1215 int force, 1216 const git_signature *who, 1217 const char *message, 1218 const git_oid *old_id, 1219 const char *old_target) 1220 { 1221 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1222 git_filebuf file = GIT_FILEBUF_INIT; 1223 int error = 0; 1224 1225 GIT_ASSERT_ARG(backend); 1226 1227 if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0) 1228 return error; 1229 1230 /* We need to perform the reflog append and old value check under the ref's lock */ 1231 if ((error = loose_lock(&file, backend, ref->name)) < 0) 1232 return error; 1233 1234 return refdb_fs_backend__write_tail(_backend, ref, &file, true, old_id, old_target, who, message); 1235 } 1236 1237 static int refdb_fs_backend__write_tail( 1238 git_refdb_backend *_backend, 1239 const git_reference *ref, 1240 git_filebuf *file, 1241 int update_reflog, 1242 const git_oid *old_id, 1243 const char *old_target, 1244 const git_signature *who, 1245 const char *message) 1246 { 1247 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1248 int error = 0, cmp = 0, should_write; 1249 const char *new_target = NULL; 1250 const git_oid *new_id = NULL; 1251 1252 if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0) 1253 goto on_error; 1254 1255 if (cmp) { 1256 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match"); 1257 error = GIT_EMODIFIED; 1258 goto on_error; 1259 } 1260 1261 if (ref->type == GIT_REFERENCE_SYMBOLIC) 1262 new_target = ref->target.symbolic; 1263 else 1264 new_id = &ref->target.oid; 1265 1266 error = cmp_old_ref(&cmp, _backend, ref->name, new_id, new_target); 1267 if (error < 0 && error != GIT_ENOTFOUND) 1268 goto on_error; 1269 1270 /* Don't update if we have the same value */ 1271 if (!error && !cmp) { 1272 error = 0; 1273 goto on_error; /* not really error */ 1274 } 1275 1276 if (update_reflog) { 1277 git_refdb *refdb; 1278 1279 if ((error = git_repository_refdb__weakptr(&refdb, backend->repo)) < 0 || 1280 (error = git_refdb_should_write_reflog(&should_write, refdb, ref)) < 0) 1281 goto on_error; 1282 1283 if (should_write) { 1284 if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0) 1285 goto on_error; 1286 if ((error = maybe_append_head(backend, ref, who, message)) < 0) 1287 goto on_error; 1288 } 1289 } 1290 1291 return loose_commit(file, ref); 1292 1293 on_error: 1294 git_filebuf_cleanup(file); 1295 return error; 1296 } 1297 1298 static int refdb_fs_backend__prune_refs( 1299 refdb_fs_backend *backend, 1300 const char *ref_name, 1301 const char *prefix) 1302 { 1303 git_buf relative_path = GIT_BUF_INIT; 1304 git_buf base_path = GIT_BUF_INIT; 1305 size_t commonlen; 1306 int error; 1307 1308 GIT_ASSERT_ARG(backend); 1309 GIT_ASSERT_ARG(ref_name); 1310 1311 if ((error = git_buf_sets(&relative_path, ref_name)) < 0) 1312 goto cleanup; 1313 1314 git_path_squash_slashes(&relative_path); 1315 if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") || 1316 (commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") || 1317 (commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) { 1318 1319 git_buf_truncate(&relative_path, commonlen); 1320 1321 if (prefix) 1322 error = git_buf_join3(&base_path, '/', 1323 backend->commonpath, prefix, 1324 git_buf_cstr(&relative_path)); 1325 else 1326 error = git_buf_joinpath(&base_path, 1327 backend->commonpath, 1328 git_buf_cstr(&relative_path)); 1329 1330 if (error < 0) 1331 goto cleanup; 1332 1333 error = git_futils_rmdir_r(ref_name + commonlen, 1334 git_buf_cstr(&base_path), 1335 GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT); 1336 1337 if (error == GIT_ENOTFOUND) 1338 error = 0; 1339 } 1340 1341 cleanup: 1342 git_buf_dispose(&relative_path); 1343 git_buf_dispose(&base_path); 1344 return error; 1345 } 1346 1347 static int refdb_fs_backend__delete( 1348 git_refdb_backend *_backend, 1349 const char *ref_name, 1350 const git_oid *old_id, const char *old_target) 1351 { 1352 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1353 git_filebuf file = GIT_FILEBUF_INIT; 1354 int error = 0; 1355 1356 GIT_ASSERT_ARG(backend); 1357 GIT_ASSERT_ARG(ref_name); 1358 1359 if ((error = loose_lock(&file, backend, ref_name)) < 0) 1360 return error; 1361 1362 if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) { 1363 git_filebuf_cleanup(&file); 1364 return error; 1365 } 1366 1367 return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target); 1368 } 1369 1370 static int loose_delete(refdb_fs_backend *backend, const char *ref_name) 1371 { 1372 git_buf loose_path = GIT_BUF_INIT; 1373 int error = 0; 1374 1375 if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0) 1376 return -1; 1377 1378 error = p_unlink(loose_path.ptr); 1379 if (error < 0 && errno == ENOENT) 1380 error = GIT_ENOTFOUND; 1381 else if (error != 0) 1382 error = -1; 1383 1384 git_buf_dispose(&loose_path); 1385 1386 return error; 1387 } 1388 1389 static int refdb_fs_backend__delete_tail( 1390 git_refdb_backend *_backend, 1391 git_filebuf *file, 1392 const char *ref_name, 1393 const git_oid *old_id, const char *old_target) 1394 { 1395 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1396 int error = 0, cmp = 0; 1397 bool packed_deleted = 0; 1398 1399 error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target); 1400 if (error < 0) 1401 goto cleanup; 1402 1403 if (cmp) { 1404 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match"); 1405 error = GIT_EMODIFIED; 1406 goto cleanup; 1407 } 1408 1409 /* 1410 * To ensure that an external observer will see either the current ref value 1411 * (because the loose ref still exists), or a missing ref (after the packed-file is 1412 * unlocked, there will be nothing left), we must ensure things happen in the 1413 * following order: 1414 * 1415 * - the packed-ref file is locked and loaded, as well as a loose one, if it exists 1416 * - we optimistically delete a packed ref, keeping track of whether it existed 1417 * - we delete the loose ref, note that we have its .lock 1418 * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked 1419 * - we should prune the path components if a loose ref was deleted 1420 * 1421 * Note that, because our packed backend doesn't expose its filesystem lock, 1422 * we might not be able to guarantee that this is what actually happens (ie. 1423 * as our current code never write packed-refs.lock, nothing stops observers 1424 * from grabbing a "stale" value from there). 1425 */ 1426 if ((error = packed_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND) 1427 goto cleanup; 1428 1429 if (error == 0) 1430 packed_deleted = 1; 1431 1432 if ((error = loose_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND) 1433 goto cleanup; 1434 1435 if (error == GIT_ENOTFOUND) { 1436 error = packed_deleted ? 0 : ref_error_notfound(ref_name); 1437 goto cleanup; 1438 } 1439 1440 cleanup: 1441 git_filebuf_cleanup(file); 1442 if (error == 0) 1443 error = refdb_fs_backend__prune_refs(backend, ref_name, ""); 1444 return error; 1445 } 1446 1447 static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name); 1448 1449 static int refdb_fs_backend__rename( 1450 git_reference **out, 1451 git_refdb_backend *_backend, 1452 const char *old_name, 1453 const char *new_name, 1454 int force, 1455 const git_signature *who, 1456 const char *message) 1457 { 1458 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1459 git_reference *old, *new = NULL; 1460 git_filebuf file = GIT_FILEBUF_INIT; 1461 int error; 1462 1463 GIT_ASSERT_ARG(backend); 1464 1465 if ((error = reference_path_available( 1466 backend, new_name, old_name, force)) < 0 || 1467 (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) 1468 return error; 1469 1470 if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { 1471 git_reference_free(old); 1472 return error; 1473 } 1474 1475 new = git_reference__realloc(&old, new_name); 1476 if (!new) { 1477 git_reference_free(old); 1478 return -1; 1479 } 1480 1481 if ((error = loose_lock(&file, backend, new->name)) < 0) { 1482 git_reference_free(new); 1483 return error; 1484 } 1485 1486 /* Try to rename the refog; it's ok if the old doesn't exist */ 1487 error = refdb_reflog_fs__rename(_backend, old_name, new_name); 1488 if (((error == 0) || (error == GIT_ENOTFOUND)) && 1489 ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { 1490 git_reference_free(new); 1491 git_filebuf_cleanup(&file); 1492 return error; 1493 } 1494 1495 if (error < 0) { 1496 git_reference_free(new); 1497 git_filebuf_cleanup(&file); 1498 return error; 1499 } 1500 1501 1502 if ((error = loose_commit(&file, new)) < 0 || out == NULL) { 1503 git_reference_free(new); 1504 return error; 1505 } 1506 1507 *out = new; 1508 return 0; 1509 } 1510 1511 static int refdb_fs_backend__compress(git_refdb_backend *_backend) 1512 { 1513 int error; 1514 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1515 1516 GIT_ASSERT_ARG(backend); 1517 1518 if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */ 1519 (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */ 1520 (error = packed_write(backend)) < 0) /* write back to disk */ 1521 return error; 1522 1523 return 0; 1524 } 1525 1526 static void refdb_fs_backend__free(git_refdb_backend *_backend) 1527 { 1528 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1529 1530 if (!backend) 1531 return; 1532 1533 git_sortedcache_free(backend->refcache); 1534 git__free(backend->gitpath); 1535 git__free(backend->commonpath); 1536 git__free(backend); 1537 } 1538 1539 static char *setup_namespace(git_repository *repo, const char *in) 1540 { 1541 git_buf path = GIT_BUF_INIT; 1542 char *parts, *start, *end, *out = NULL; 1543 1544 if (!in) 1545 goto done; 1546 1547 git_buf_puts(&path, in); 1548 1549 /* if the repo is not namespaced, nothing else to do */ 1550 if (repo->namespace == NULL) { 1551 out = git_buf_detach(&path); 1552 goto done; 1553 } 1554 1555 parts = end = git__strdup(repo->namespace); 1556 if (parts == NULL) 1557 goto done; 1558 1559 /* 1560 * From `man gitnamespaces`: 1561 * namespaces which include a / will expand to a hierarchy 1562 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store 1563 * refs under refs/namespaces/foo/refs/namespaces/bar/ 1564 */ 1565 while ((start = git__strsep(&end, "/")) != NULL) 1566 git_buf_printf(&path, "refs/namespaces/%s/", start); 1567 1568 git_buf_printf(&path, "refs/namespaces/%s/refs", end); 1569 git__free(parts); 1570 1571 /* Make sure that the folder with the namespace exists */ 1572 if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777, 1573 GIT_MKDIR_PATH, NULL) < 0) 1574 goto done; 1575 1576 /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */ 1577 git_buf_rtruncate_at_char(&path, '/'); 1578 out = git_buf_detach(&path); 1579 1580 done: 1581 git_buf_dispose(&path); 1582 return out; 1583 } 1584 1585 static int reflog_alloc(git_reflog **reflog, const char *name) 1586 { 1587 git_reflog *log; 1588 1589 *reflog = NULL; 1590 1591 log = git__calloc(1, sizeof(git_reflog)); 1592 GIT_ERROR_CHECK_ALLOC(log); 1593 1594 log->ref_name = git__strdup(name); 1595 GIT_ERROR_CHECK_ALLOC(log->ref_name); 1596 1597 if (git_vector_init(&log->entries, 0, NULL) < 0) { 1598 git__free(log->ref_name); 1599 git__free(log); 1600 return -1; 1601 } 1602 1603 *reflog = log; 1604 1605 return 0; 1606 } 1607 1608 static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) 1609 { 1610 git_parse_ctx parser = GIT_PARSE_CTX_INIT; 1611 1612 if ((git_parse_ctx_init(&parser, buf, buf_size)) < 0) 1613 return -1; 1614 1615 for (; parser.remain_len; git_parse_advance_line(&parser)) { 1616 git_reflog_entry *entry; 1617 const char *sig; 1618 char c; 1619 1620 entry = git__calloc(1, sizeof(*entry)); 1621 GIT_ERROR_CHECK_ALLOC(entry); 1622 entry->committer = git__calloc(1, sizeof(*entry->committer)); 1623 GIT_ERROR_CHECK_ALLOC(entry->committer); 1624 1625 if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 || 1626 git_parse_advance_expected(&parser, " ", 1) < 0 || 1627 git_parse_advance_oid(&entry->oid_cur, &parser) < 0) 1628 goto next; 1629 1630 sig = parser.line; 1631 while (git_parse_peek(&c, &parser, 0) == 0 && c != '\t' && c != '\n') 1632 git_parse_advance_chars(&parser, 1); 1633 1634 if (git_signature__parse(entry->committer, &sig, parser.line, NULL, 0) < 0) 1635 goto next; 1636 1637 if (c == '\t') { 1638 size_t len; 1639 git_parse_advance_chars(&parser, 1); 1640 1641 len = parser.line_len; 1642 if (parser.line[len - 1] == '\n') 1643 len--; 1644 1645 entry->msg = git__strndup(parser.line, len); 1646 GIT_ERROR_CHECK_ALLOC(entry->msg); 1647 } 1648 1649 if ((git_vector_insert(&log->entries, entry)) < 0) { 1650 git_reflog_entry__free(entry); 1651 return -1; 1652 } 1653 1654 continue; 1655 1656 next: 1657 git_reflog_entry__free(entry); 1658 } 1659 1660 return 0; 1661 } 1662 1663 static int create_new_reflog_file(const char *filepath) 1664 { 1665 int fd, error; 1666 1667 if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0) 1668 return error; 1669 1670 if ((fd = p_open(filepath, 1671 O_WRONLY | O_CREAT, 1672 GIT_REFLOG_FILE_MODE)) < 0) 1673 return -1; 1674 1675 return p_close(fd); 1676 } 1677 1678 GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name) 1679 { 1680 if (strcmp(name, GIT_HEAD_FILE) == 0) 1681 return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name); 1682 return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name); 1683 } 1684 1685 static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name) 1686 { 1687 refdb_fs_backend *backend; 1688 git_repository *repo; 1689 git_buf path = GIT_BUF_INIT; 1690 int error; 1691 1692 GIT_ASSERT_ARG(_backend && name); 1693 1694 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1695 repo = backend->repo; 1696 1697 if ((error = retrieve_reflog_path(&path, repo, name)) < 0) 1698 return error; 1699 1700 error = create_new_reflog_file(git_buf_cstr(&path)); 1701 git_buf_dispose(&path); 1702 1703 return error; 1704 } 1705 1706 static int has_reflog(git_repository *repo, const char *name) 1707 { 1708 int ret = 0; 1709 git_buf path = GIT_BUF_INIT; 1710 1711 if (retrieve_reflog_path(&path, repo, name) < 0) 1712 goto cleanup; 1713 1714 ret = git_path_isfile(git_buf_cstr(&path)); 1715 1716 cleanup: 1717 git_buf_dispose(&path); 1718 return ret; 1719 } 1720 1721 static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *name) 1722 { 1723 refdb_fs_backend *backend; 1724 1725 GIT_ASSERT_ARG(_backend); 1726 GIT_ASSERT_ARG(name); 1727 1728 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1729 1730 return has_reflog(backend->repo, name); 1731 } 1732 1733 static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name) 1734 { 1735 int error = -1; 1736 git_buf log_path = GIT_BUF_INIT; 1737 git_buf log_file = GIT_BUF_INIT; 1738 git_reflog *log = NULL; 1739 git_repository *repo; 1740 refdb_fs_backend *backend; 1741 1742 GIT_ASSERT_ARG(out); 1743 GIT_ASSERT_ARG(_backend); 1744 GIT_ASSERT_ARG(name); 1745 1746 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1747 repo = backend->repo; 1748 1749 if (reflog_alloc(&log, name) < 0) 1750 return -1; 1751 1752 if (retrieve_reflog_path(&log_path, repo, name) < 0) 1753 goto cleanup; 1754 1755 error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path)); 1756 if (error < 0 && error != GIT_ENOTFOUND) 1757 goto cleanup; 1758 1759 if ((error == GIT_ENOTFOUND) && 1760 ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0)) 1761 goto cleanup; 1762 1763 if ((error = reflog_parse(log, 1764 git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0) 1765 goto cleanup; 1766 1767 *out = log; 1768 goto success; 1769 1770 cleanup: 1771 git_reflog_free(log); 1772 1773 success: 1774 git_buf_dispose(&log_file); 1775 git_buf_dispose(&log_path); 1776 1777 return error; 1778 } 1779 1780 static int serialize_reflog_entry( 1781 git_buf *buf, 1782 const git_oid *oid_old, 1783 const git_oid *oid_new, 1784 const git_signature *committer, 1785 const char *msg) 1786 { 1787 char raw_old[GIT_OID_HEXSZ+1]; 1788 char raw_new[GIT_OID_HEXSZ+1]; 1789 1790 git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old); 1791 git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new); 1792 1793 git_buf_clear(buf); 1794 1795 git_buf_puts(buf, raw_old); 1796 git_buf_putc(buf, ' '); 1797 git_buf_puts(buf, raw_new); 1798 1799 git_signature__writebuf(buf, " ", committer); 1800 1801 /* drop trailing LF */ 1802 git_buf_rtrim(buf); 1803 1804 if (msg) { 1805 size_t i; 1806 1807 git_buf_putc(buf, '\t'); 1808 git_buf_puts(buf, msg); 1809 1810 for (i = 0; i < buf->size - 2; i++) 1811 if (buf->ptr[i] == '\n') 1812 buf->ptr[i] = ' '; 1813 git_buf_rtrim(buf); 1814 } 1815 1816 git_buf_putc(buf, '\n'); 1817 1818 return git_buf_oom(buf); 1819 } 1820 1821 static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char *refname) 1822 { 1823 git_repository *repo; 1824 git_buf log_path = GIT_BUF_INIT; 1825 int error; 1826 1827 repo = backend->repo; 1828 1829 if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { 1830 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", refname); 1831 return GIT_EINVALIDSPEC; 1832 } 1833 1834 if (retrieve_reflog_path(&log_path, repo, refname) < 0) 1835 return -1; 1836 1837 if (!git_path_isfile(git_buf_cstr(&log_path))) { 1838 git_error_set(GIT_ERROR_INVALID, 1839 "log file for reference '%s' doesn't exist", refname); 1840 error = -1; 1841 goto cleanup; 1842 } 1843 1844 error = git_filebuf_open(file, git_buf_cstr(&log_path), 0, GIT_REFLOG_FILE_MODE); 1845 1846 cleanup: 1847 git_buf_dispose(&log_path); 1848 1849 return error; 1850 } 1851 1852 static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflog) 1853 { 1854 int error = -1; 1855 unsigned int i; 1856 git_reflog_entry *entry; 1857 refdb_fs_backend *backend; 1858 git_buf log = GIT_BUF_INIT; 1859 git_filebuf fbuf = GIT_FILEBUF_INIT; 1860 1861 GIT_ASSERT_ARG(_backend); 1862 GIT_ASSERT_ARG(reflog); 1863 1864 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1865 1866 if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0) 1867 return -1; 1868 1869 git_vector_foreach(&reflog->entries, i, entry) { 1870 if (serialize_reflog_entry(&log, &(entry->oid_old), &(entry->oid_cur), entry->committer, entry->msg) < 0) 1871 goto cleanup; 1872 1873 if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0) 1874 goto cleanup; 1875 } 1876 1877 error = git_filebuf_commit(&fbuf); 1878 goto success; 1879 1880 cleanup: 1881 git_filebuf_cleanup(&fbuf); 1882 1883 success: 1884 git_buf_dispose(&log); 1885 1886 return error; 1887 } 1888 1889 /* Append to the reflog, must be called under reference lock */ 1890 static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message) 1891 { 1892 int error, is_symbolic, open_flags; 1893 git_oid old_id = {{0}}, new_id = {{0}}; 1894 git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; 1895 git_repository *repo = backend->repo; 1896 1897 is_symbolic = ref->type == GIT_REFERENCE_SYMBOLIC; 1898 1899 /* "normal" symbolic updates do not write */ 1900 if (is_symbolic && 1901 strcmp(ref->name, GIT_HEAD_FILE) && 1902 !(old && new)) 1903 return 0; 1904 1905 /* From here on is_symbolic also means that it's HEAD */ 1906 1907 if (old) { 1908 git_oid_cpy(&old_id, old); 1909 } else { 1910 error = git_reference_name_to_id(&old_id, repo, ref->name); 1911 if (error < 0 && error != GIT_ENOTFOUND) 1912 return error; 1913 } 1914 1915 if (new) { 1916 git_oid_cpy(&new_id, new); 1917 } else { 1918 if (!is_symbolic) { 1919 git_oid_cpy(&new_id, git_reference_target(ref)); 1920 } else { 1921 error = git_reference_name_to_id(&new_id, repo, git_reference_symbolic_target(ref)); 1922 if (error < 0 && error != GIT_ENOTFOUND) 1923 return error; 1924 /* detaching HEAD does not create an entry */ 1925 if (error == GIT_ENOTFOUND) 1926 return 0; 1927 1928 git_error_clear(); 1929 } 1930 } 1931 1932 if ((error = serialize_reflog_entry(&buf, &old_id, &new_id, who, message)) < 0) 1933 goto cleanup; 1934 1935 if ((error = retrieve_reflog_path(&path, repo, ref->name)) < 0) 1936 goto cleanup; 1937 1938 if (((error = git_futils_mkpath2file(git_buf_cstr(&path), 0777)) < 0) && 1939 (error != GIT_EEXISTS)) { 1940 goto cleanup; 1941 } 1942 1943 /* If the new branch matches part of the namespace of a previously deleted branch, 1944 * there maybe an obsolete/unused directory (or directory hierarchy) in the way. 1945 */ 1946 if (git_path_isdir(git_buf_cstr(&path))) { 1947 if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) { 1948 if (error == GIT_ENOTFOUND) 1949 error = 0; 1950 } else if (git_path_isdir(git_buf_cstr(&path))) { 1951 git_error_set(GIT_ERROR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder", 1952 ref->name); 1953 error = GIT_EDIRECTORY; 1954 } 1955 1956 if (error != 0) 1957 goto cleanup; 1958 } 1959 1960 open_flags = O_WRONLY | O_CREAT | O_APPEND; 1961 1962 if (backend->fsync) 1963 open_flags |= O_FSYNC; 1964 1965 error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE); 1966 1967 cleanup: 1968 git_buf_dispose(&buf); 1969 git_buf_dispose(&path); 1970 1971 return error; 1972 } 1973 1974 static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name) 1975 { 1976 int error = 0, fd; 1977 git_buf old_path = GIT_BUF_INIT; 1978 git_buf new_path = GIT_BUF_INIT; 1979 git_buf temp_path = GIT_BUF_INIT; 1980 git_buf normalized = GIT_BUF_INIT; 1981 git_repository *repo; 1982 refdb_fs_backend *backend; 1983 1984 GIT_ASSERT_ARG(_backend); 1985 GIT_ASSERT_ARG(old_name); 1986 GIT_ASSERT_ARG(new_name); 1987 1988 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1989 repo = backend->repo; 1990 1991 if ((error = git_reference__normalize_name( 1992 &normalized, new_name, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL)) < 0) 1993 return error; 1994 1995 if (git_buf_joinpath(&temp_path, repo->gitdir, GIT_REFLOG_DIR) < 0) 1996 return -1; 1997 1998 if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), old_name) < 0) 1999 return -1; 2000 2001 if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), git_buf_cstr(&normalized)) < 0) 2002 return -1; 2003 2004 if (!git_path_exists(git_buf_cstr(&old_path))) { 2005 error = GIT_ENOTFOUND; 2006 goto cleanup; 2007 } 2008 2009 /* 2010 * Move the reflog to a temporary place. This two-phase renaming is required 2011 * in order to cope with funny renaming use cases when one tries to move a reference 2012 * to a partially colliding namespace: 2013 * - a/b -> a/b/c 2014 * - a/b/c/d -> a/b/c 2015 */ 2016 if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0) 2017 return -1; 2018 2019 if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path), GIT_REFLOG_FILE_MODE)) < 0) { 2020 error = -1; 2021 goto cleanup; 2022 } 2023 2024 p_close(fd); 2025 2026 if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) { 2027 git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name); 2028 error = -1; 2029 goto cleanup; 2030 } 2031 2032 if (git_path_isdir(git_buf_cstr(&new_path)) && 2033 (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) { 2034 error = -1; 2035 goto cleanup; 2036 } 2037 2038 if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) { 2039 error = -1; 2040 goto cleanup; 2041 } 2042 2043 if (p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)) < 0) { 2044 git_error_set(GIT_ERROR_OS, "failed to rename reflog for %s", new_name); 2045 error = -1; 2046 } 2047 2048 cleanup: 2049 git_buf_dispose(&temp_path); 2050 git_buf_dispose(&old_path); 2051 git_buf_dispose(&new_path); 2052 git_buf_dispose(&normalized); 2053 2054 return error; 2055 } 2056 2057 static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name) 2058 { 2059 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 2060 git_buf path = GIT_BUF_INIT; 2061 int error; 2062 2063 GIT_ASSERT_ARG(_backend); 2064 GIT_ASSERT_ARG(name); 2065 2066 if ((error = retrieve_reflog_path(&path, backend->repo, name)) < 0) 2067 goto out; 2068 2069 if (!git_path_exists(path.ptr)) 2070 goto out; 2071 2072 if ((error = p_unlink(path.ptr)) < 0) 2073 goto out; 2074 2075 error = refdb_fs_backend__prune_refs(backend, name, GIT_REFLOG_DIR); 2076 2077 out: 2078 git_buf_dispose(&path); 2079 2080 return error; 2081 } 2082 2083 int git_refdb_backend_fs( 2084 git_refdb_backend **backend_out, 2085 git_repository *repository) 2086 { 2087 int t = 0; 2088 git_buf gitpath = GIT_BUF_INIT; 2089 refdb_fs_backend *backend; 2090 2091 backend = git__calloc(1, sizeof(refdb_fs_backend)); 2092 GIT_ERROR_CHECK_ALLOC(backend); 2093 2094 if (git_refdb_init_backend(&backend->parent, GIT_REFDB_BACKEND_VERSION) < 0) 2095 goto fail; 2096 2097 backend->repo = repository; 2098 2099 if (repository->gitdir) { 2100 backend->gitpath = setup_namespace(repository, repository->gitdir); 2101 2102 if (backend->gitpath == NULL) 2103 goto fail; 2104 } 2105 2106 if (repository->commondir) { 2107 backend->commonpath = setup_namespace(repository, repository->commondir); 2108 2109 if (backend->commonpath == NULL) 2110 goto fail; 2111 } 2112 2113 if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 || 2114 git_sortedcache_new( 2115 &backend->refcache, offsetof(struct packref, name), 2116 NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0) 2117 goto fail; 2118 2119 git_buf_dispose(&gitpath); 2120 2121 if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) { 2122 backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE; 2123 backend->direach_flags |= GIT_PATH_DIR_IGNORE_CASE; 2124 } 2125 if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) { 2126 backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; 2127 backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE; 2128 } 2129 if ((!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) || 2130 git_repository__fsync_gitdir) 2131 backend->fsync = 1; 2132 backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS; 2133 2134 backend->parent.exists = &refdb_fs_backend__exists; 2135 backend->parent.lookup = &refdb_fs_backend__lookup; 2136 backend->parent.iterator = &refdb_fs_backend__iterator; 2137 backend->parent.write = &refdb_fs_backend__write; 2138 backend->parent.del = &refdb_fs_backend__delete; 2139 backend->parent.rename = &refdb_fs_backend__rename; 2140 backend->parent.compress = &refdb_fs_backend__compress; 2141 backend->parent.lock = &refdb_fs_backend__lock; 2142 backend->parent.unlock = &refdb_fs_backend__unlock; 2143 backend->parent.has_log = &refdb_reflog_fs__has_log; 2144 backend->parent.ensure_log = &refdb_reflog_fs__ensure_log; 2145 backend->parent.free = &refdb_fs_backend__free; 2146 backend->parent.reflog_read = &refdb_reflog_fs__read; 2147 backend->parent.reflog_write = &refdb_reflog_fs__write; 2148 backend->parent.reflog_rename = &refdb_reflog_fs__rename; 2149 backend->parent.reflog_delete = &refdb_reflog_fs__delete; 2150 2151 *backend_out = (git_refdb_backend *)backend; 2152 return 0; 2153 2154 fail: 2155 git_buf_dispose(&gitpath); 2156 git__free(backend->gitpath); 2157 git__free(backend->commonpath); 2158 git__free(backend); 2159 return -1; 2160 } 2161