/src/refdb_fs.c
C | 2196 lines | 1536 code | 465 blank | 195 comment | 412 complexity | 7d6548a63f9b791a35ef48bc6225a580 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
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 33enum { 34 PACKREF_HAS_PEEL = 1, 35 PACKREF_WAS_LOOSE = 2, 36 PACKREF_CANNOT_PEEL = 4, 37 PACKREF_SHADOWED = 8, 38}; 39 40enum { 41 PEELING_NONE = 0, 42 PEELING_STANDARD, 43 PEELING_FULL 44}; 45 46struct packref { 47 git_oid oid; 48 git_oid peel; 49 char flags; 50 char name[GIT_FLEX_ARRAY]; 51}; 52 53typedef 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 69static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name); 70 71static 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 77static 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 190parse_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 200static 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 217corrupted: 218 git_error_set(GIT_ERROR_REFERENCE, "corrupted loose reference file: %s", filename); 219 return -1; 220} 221 222static 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 234static 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 268done: 269 git_buf_dispose(&ref_file); 270 return error; 271} 272 273static 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 */ 304static 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 325static 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 assert(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 354out: 355 git_buf_dispose(&ref_path); 356 return error; 357} 358 359static 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 */ 387static 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 393static 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 433static 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 439static 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 467static 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 assert(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 490typedef 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 503static 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 513static 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 590static 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 631static 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 674static 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 assert(backend); 682 683 iter = git__calloc(1, sizeof(refdb_fs_iter)); 684 GIT_ERROR_CHECK_ALLOC(iter); 685 686 git_pool_init(&iter->pool, 1); 687 688 if ((error = git_vector_init(&iter->loose, 8, NULL)) < 0) 689 goto out; 690 691 if (glob != NULL && 692 (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL) { 693 error = GIT_ERROR_NOMEMORY; 694 goto out; 695 } 696 697 if ((error = iter_load_loose_paths(backend, iter)) < 0) 698 goto out; 699 700 if ((error = packed_reload(backend)) < 0) 701 goto out; 702 703 if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0) 704 goto out; 705 706 iter->parent.next = refdb_fs_backend__iterator_next; 707 iter->parent.next_name = refdb_fs_backend__iterator_next_name; 708 iter->parent.free = refdb_fs_backend__iterator_free; 709 710 *out = (git_reference_iterator *)iter; 711out: 712 if (error) 713 refdb_fs_backend__iterator_free((git_reference_iterator *)iter); 714 return error; 715} 716 717static bool ref_is_available( 718 const char *old_ref, const char *new_ref, const char *this_ref) 719{ 720 if (old_ref == NULL || strcmp(old_ref, this_ref)) { 721 size_t reflen = strlen(this_ref); 722 size_t newlen = strlen(new_ref); 723 size_t cmplen = reflen < newlen ? reflen : newlen; 724 const char *lead = reflen < newlen ? new_ref : this_ref; 725 726 if (!strncmp(new_ref, this_ref, cmplen) && lead[cmplen] == '/') { 727 return false; 728 } 729 } 730 731 return true; 732} 733 734static int reference_path_available( 735 refdb_fs_backend *backend, 736 const char *new_ref, 737 const char* old_ref, 738 int force) 739{ 740 size_t i; 741 int error; 742 743 if ((error = packed_reload(backend)) < 0) 744 return error; 745 746 if (!force) { 747 int exists; 748 749 if ((error = refdb_fs_backend__exists( 750 &exists, (git_refdb_backend *)backend, new_ref)) < 0) { 751 return error; 752 } 753 754 if (exists) { 755 git_error_set(GIT_ERROR_REFERENCE, 756 "failed to write reference '%s': a reference with " 757 "that name already exists.", new_ref); 758 return GIT_EEXISTS; 759 } 760 } 761 762 git_sortedcache_rlock(backend->refcache); 763 764 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) { 765 struct packref *ref = git_sortedcache_entry(backend->refcache, i); 766 767 if (ref && !ref_is_available(old_ref, new_ref, ref->name)) { 768 git_sortedcache_runlock(backend->refcache); 769 git_error_set(GIT_ERROR_REFERENCE, 770 "path to reference '%s' collides with existing one", new_ref); 771 return -1; 772 } 773 } 774 775 git_sortedcache_runlock(backend->refcache); 776 return 0; 777} 778 779static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name) 780{ 781 int error, filebuf_flags; 782 git_buf ref_path = GIT_BUF_INIT; 783 const char *basedir; 784 785 assert(file && backend && name); 786 787 if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { 788 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", name); 789 return GIT_EINVALIDSPEC; 790 } 791 792 if (is_per_worktree_ref(name)) 793 basedir = backend->gitpath; 794 else 795 basedir = backend->commonpath; 796 797 /* Remove a possibly existing empty directory hierarchy 798 * which name would collide with the reference name 799 */ 800 if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0) 801 return error; 802 803 if (git_buf_joinpath(&ref_path, basedir, name) < 0) 804 return -1; 805 806 filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS; 807 if (backend->fsync) 808 filebuf_flags |= GIT_FILEBUF_FSYNC; 809 810 error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE); 811 812 if (error == GIT_EDIRECTORY) 813 git_error_set(GIT_ERROR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name); 814 815 git_buf_dispose(&ref_path); 816 return error; 817} 818 819static int loose_commit(git_filebuf *file, const git_reference *ref) 820{ 821 assert(file && ref); 822 823 if (ref->type == GIT_REFERENCE_DIRECT) { 824 char oid[GIT_OID_HEXSZ + 1]; 825 git_oid_nfmt(oid, sizeof(oid), &ref->target.oid); 826 827 git_filebuf_printf(file, "%s\n", oid); 828 } else if (ref->type == GIT_REFERENCE_SYMBOLIC) { 829 git_filebuf_printf(file, GIT_SYMREF "%s\n", ref->target.symbolic); 830 } else { 831 assert(0); /* don't let this happen */ 832 } 833 834 return git_filebuf_commit(file); 835} 836 837static int refdb_fs_backend__lock(void **out, git_refdb_backend *_backend, const char *refname) 838{ 839 int error; 840 git_filebuf *lock; 841 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 842 843 lock = git__calloc(1, sizeof(git_filebuf)); 844 GIT_ERROR_CHECK_ALLOC(lock); 845 846 if ((error = loose_lock(lock, backend, refname)) < 0) { 847 git__free(lock); 848 return error; 849 } 850 851 *out = lock; 852 return 0; 853} 854 855static int refdb_fs_backend__write_tail( 856 git_refdb_backend *_backend, 857 const git_reference *ref, 858 git_filebuf *file, 859 int update_reflog, 860 const git_oid *old_id, 861 const char *old_target, 862 const git_signature *who, 863 const char *message); 864 865static int refdb_fs_backend__delete_tail( 866 git_refdb_backend *_backend, 867 git_filebuf *file, 868 const char *ref_name, 869 const git_oid *old_id, 870 const char *old_target); 871 872static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog, 873 const git_reference *ref, const git_signature *sig, const char *message) 874{ 875 git_filebuf *lock = (git_filebuf *) payload; 876 int error = 0; 877 878 if (success == 2) 879 error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL); 880 else if (success) 881 error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, NULL, NULL, sig, message); 882 else 883 git_filebuf_cleanup(lock); 884 885 git__free(lock); 886 return error; 887} 888 889/* 890 * Find out what object this reference resolves to. 891 * 892 * For references that point to a 'big' tag (e.g. an 893 * actual tag object on the repository), we need to 894 * cache on the packfile the OID of the object to 895 * which that 'big tag' is pointing to. 896 */ 897static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) 898{ 899 git_object *object; 900 901 if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL) 902 return 0; 903 904 /* 905 * Find the tagged object in the repository 906 */ 907 if (git_object_lookup(&object, backend->repo, &ref->oid, GIT_OBJECT_ANY) < 0) 908 return -1; 909 910 /* 911 * If the tagged object is a Tag object, we need to resolve it; 912 * if the ref is actually a 'weak' ref, we don't need to resolve 913 * anything. 914 */ 915 if (git_object_type(object) == GIT_OBJECT_TAG) { 916 git_tag *tag = (git_tag *)object; 917 918 /* 919 * Find the object pointed at by this tag 920 */ 921 git_oid_cpy(&ref->peel, git_tag_target_id(tag)); 922 ref->flags |= PACKREF_HAS_PEEL; 923 924 /* 925 * The reference has now cached the resolved OID, and is 926 * marked at such. When written to the packfile, it'll be 927 * accompanied by this resolved oid 928 */ 929 } 930 931 git_object_free(object); 932 return 0; 933} 934 935/* 936 * Write a single reference into a packfile 937 */ 938static int packed_write_ref(struct packref *ref, git_filebuf *file) 939{ 940 char oid[GIT_OID_HEXSZ + 1]; 941 git_oid_nfmt(oid, sizeof(oid), &ref->oid); 942 943 /* 944 * For references that peel to an object in the repo, we must 945 * write the resulting peel on a separate line, e.g. 946 * 947 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4 948 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100 949 * 950 * This obviously only applies to tags. 951 * The required peels have already been loaded into `ref->peel_target`. 952 */ 953 if (ref->flags & PACKREF_HAS_PEEL) { 954 char peel[GIT_OID_HEXSZ + 1]; 955 git_oid_nfmt(peel, sizeof(peel), &ref->peel); 956 957 if (git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel) < 0) 958 return -1; 959 } else { 960 if (git_filebuf_printf(file, "%s %s\n", oid, ref->name) < 0) 961 return -1; 962 } 963 964 return 0; 965} 966 967/* 968 * Remove all loose references 969 * 970 * Once we have successfully written a packfile, 971 * all the loose references that were packed must be 972 * removed from disk. 973 * 974 * This is a dangerous method; make sure the packfile 975 * is well-written, because we are destructing references 976 * here otherwise. 977 */ 978static int packed_remove_loose(refdb_fs_backend *backend) 979{ 980 size_t i; 981 git_filebuf lock = GIT_FILEBUF_INIT; 982 git_buf ref_content = GIT_BUF_INIT; 983 int error = 0; 984 985 /* backend->refcache is already locked when this is called */ 986 987 for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) { 988 struct packref *ref = git_sortedcache_entry(backend->refcache, i); 989 git_oid current_id; 990 991 if (!ref || !(ref->flags & PACKREF_WAS_LOOSE)) 992 continue; 993 994 git_filebuf_cleanup(&lock); 995 996 /* We need to stop anybody from updating the ref while we try to do a safe delete */ 997 error = loose_lock(&lock, backend, ref->name); 998 /* If someone else is updating it, let them do it */ 999 if (error == GIT_EEXISTS || error == GIT_ENOTFOUND) 1000 continue; 1001 1002 if (error < 0) { 1003 git_buf_dispose(&ref_content); 1004 git_error_set(GIT_ERROR_REFERENCE, "failed to lock loose reference '%s'", ref->name); 1005 return error; 1006 } 1007 1008 error = git_futils_readbuffer(&ref_content, lock.path_original); 1009 /* Someone else beat us to cleaning up the ref, let's simply continue */ 1010 if (error == GIT_ENOTFOUND) 1011 continue; 1012 1013 /* This became a symref between us packing and trying to delete it, so ignore it */ 1014 if (!git__prefixcmp(ref_content.ptr, GIT_SYMREF)) 1015 continue; 1016 1017 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */ 1018 if (loose_parse_oid(¤t_id, lock.path_original, &ref_content) < 0) 1019 continue; 1020 1021 /* If the ref moved since we packed it, we must not delete it */ 1022 if (!git_oid_equal(¤t_id, &ref->oid)) 1023 continue; 1024 1025 /* 1026 * if we fail to remove a single file, this is *not* good, 1027 * but we should keep going and remove as many as possible. 1028 * If we fail to remove, the ref is still in the old state, so 1029 * we haven't lost information. 1030 */ 1031 p_unlink(lock.path_original); 1032 } 1033 1034 git_buf_dispose(&ref_content); 1035 git_filebuf_cleanup(&lock); 1036 return 0; 1037} 1038 1039/* 1040 * Write all the contents in the in-memory packfile to disk. 1041 */ 1042static int packed_write(refdb_fs_backend *backend) 1043{ 1044 git_sortedcache *refcache = backend->refcache; 1045 git_filebuf pack_file = GIT_FILEBUF_INIT; 1046 int error, open_flags = 0; 1047 size_t i; 1048 1049 /* lock the cache to updates while we do this */ 1050 if ((error = git_sortedcache_wlock(refcache)) < 0) 1051 return error; 1052 1053 if (backend->fsync) 1054 open_flags = GIT_FILEBUF_FSYNC; 1055 1056 /* Open the file! */ 1057 if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0) 1058 goto fail; 1059 1060 /* Packfiles have a header... apparently 1061 * This is in fact not required, but we might as well print it 1062 * just for kicks */ 1063 if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < 0) 1064 goto fail; 1065 1066 for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) { 1067 struct packref *ref = git_sortedcache_entry(refcache, i); 1068 assert(ref); 1069 1070 if ((error = packed_find_peel(backend, ref)) < 0) 1071 goto fail; 1072 1073 if ((error = packed_write_ref(ref, &pack_file)) < 0) 1074 goto fail; 1075 } 1076 1077 /* if we've written all the references properly, we can commit 1078 * the packfile to make the changes effective */ 1079 if ((error = git_filebuf_commit(&pack_file)) < 0) 1080 goto fail; 1081 1082 /* when and only when the packfile has been properly written, 1083 * we can go ahead and remove the loose refs */ 1084 if ((error = packed_remove_loose(backend)) < 0) 1085 goto fail; 1086 1087 git_sortedcache_updated(refcache); 1088 git_sortedcache_wunlock(refcache); 1089 1090 /* we're good now */ 1091 return 0; 1092 1093fail: 1094 git_filebuf_cleanup(&pack_file); 1095 git_sortedcache_wunlock(refcache); 1096 1097 return error; 1098} 1099 1100static int packed_delete(refdb_fs_backend *backend, const char *ref_name) 1101{ 1102 size_t pack_pos; 1103 int error, found = 0; 1104 1105 if ((error = packed_reload(backend)) < 0) 1106 goto cleanup; 1107 1108 if ((error = git_sortedcache_wlock(backend->refcache)) < 0) 1109 goto cleanup; 1110 1111 /* If a packed reference exists, remove it from the packfile and repack if necessary */ 1112 error = git_sortedcache_lookup_index(&pack_pos, backend->refcache, ref_name); 1113 if (error == 0) { 1114 error = git_sortedcache_remove(backend->refcache, pack_pos); 1115 found = 1; 1116 } 1117 if (error == GIT_ENOTFOUND) 1118 error = 0; 1119 1120 git_sortedcache_wunlock(backend->refcache); 1121 1122 if (found) 1123 error = packed_write(backend); 1124 1125cleanup: 1126 return error; 1127} 1128 1129static 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); 1130static int has_reflog(git_repository *repo, const char *name); 1131 1132static int should_write_reflog(int *write, git_repository *repo, const char *name) 1133{ 1134 int error, logall; 1135 1136 error = git_repository__configmap_lookup(&logall, repo, GIT_CONFIGMAP_LOGALLREFUPDATES); 1137 if (error < 0) 1138 return error; 1139 1140 /* Defaults to the opposite of the repo being bare */ 1141 if (logall == GIT_LOGALLREFUPDATES_UNSET) 1142 logall = !git_repository_is_bare(repo); 1143 1144 *write = 0; 1145 switch (logall) { 1146 case GIT_LOGALLREFUPDATES_FALSE: 1147 *write = 0; 1148 break; 1149 1150 case GIT_LOGALLREFUPDATES_TRUE: 1151 /* Only write if it already has a log, 1152 * or if it's under heads/, remotes/ or notes/ 1153 */ 1154 *write = has_reflog(repo, name) || 1155 !git__prefixcmp(name, GIT_REFS_HEADS_DIR) || 1156 !git__strcmp(name, GIT_HEAD_FILE) || 1157 !git__prefixcmp(name, GIT_REFS_REMOTES_DIR) || 1158 !git__prefixcmp(name, GIT_REFS_NOTES_DIR); 1159 break; 1160 1161 case GIT_LOGALLREFUPDATES_ALWAYS: 1162 *write = 1; 1163 break; 1164 } 1165 1166 return 0; 1167} 1168 1169static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name, 1170 const git_oid *old_id, const char *old_target) 1171{ 1172 int error = 0; 1173 git_reference *old_ref = NULL; 1174 1175 *cmp = 0; 1176 /* It "matches" if there is no old value to compare against */ 1177 if (!old_id && !old_target) 1178 return 0; 1179 1180 if ((error = refdb_fs_backend__lookup(&old_ref, backend, name)) < 0) 1181 goto out; 1182 1183 /* If the types don't match, there's no way the values do */ 1184 if (old_id && old_ref->type != GIT_REFERENCE_DIRECT) { 1185 *cmp = -1; 1186 goto out; 1187 } 1188 if (old_target && old_ref->type != GIT_REFERENCE_SYMBOLIC) { 1189 *cmp = 1; 1190 goto out; 1191 } 1192 1193 if (old_id && old_ref->type == GIT_REFERENCE_DIRECT) 1194 *cmp = git_oid_cmp(old_id, &old_ref->target.oid); 1195 1196 if (old_target && old_ref->type == GIT_REFERENCE_SYMBOLIC) 1197 *cmp = git__strcmp(old_target, old_ref->target.symbolic); 1198 1199out: 1200 git_reference_free(old_ref); 1201 1202 return error; 1203} 1204 1205/* 1206 * The git.git comment regarding this, for your viewing pleasure: 1207 * 1208 * Special hack: If a branch is updated directly and HEAD 1209 * points to it (may happen on the remote side of a push 1210 * for example) then logically the HEAD reflog should be 1211 * updated too. 1212 * A generic solution implies reverse symref information, 1213 * but finding all symrefs pointing to the given branch 1214 * would be rather costly for this rare event (the direct 1215 * update of a branch) to be worth it. So let's cheat and 1216 * check with HEAD only which should cover 99% of all usage 1217 * scenarios (even 100% of the default ones). 1218 */ 1219static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message) 1220{ 1221 int error; 1222 git_oid old_id; 1223 git_reference *tmp = NULL, *head = NULL, *peeled = NULL; 1224 const char *name; 1225 1226 if (ref->type == GIT_REFERENCE_SYMBOLIC) 1227 return 0; 1228 1229 /* if we can't resolve, we use {0}*40 as old id */ 1230 if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0) 1231 memset(&old_id, 0, sizeof(old_id)); 1232 1233 if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0) 1234 return error; 1235 1236 if (git_reference_type(head) == GIT_REFERENCE_DIRECT) 1237 goto cleanup; 1238 1239 if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0) 1240 goto cleanup; 1241 1242 /* Go down the symref chain until we find the branch */ 1243 while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) { 1244 error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp)); 1245 if (error < 0) 1246 break; 1247 1248 git_reference_free(tmp); 1249 tmp = peeled; 1250 } 1251 1252 if (error == GIT_ENOTFOUND) { 1253 error = 0; 1254 name = git_reference_symbolic_target(tmp); 1255 } else if (error < 0) { 1256 goto cleanup; 1257 } else { 1258 name = git_reference_name(tmp); 1259 } 1260 1261 if (strcmp(name, ref->name)) 1262 goto cleanup; 1263 1264 error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message); 1265 1266cleanup: 1267 git_reference_free(tmp); 1268 git_reference_free(head); 1269 return error; 1270} 1271 1272static int refdb_fs_backend__write( 1273 git_refdb_backend *_backend, 1274 const git_reference *ref, 1275 int force, 1276 const git_signature *who, 1277 const char *message, 1278 const git_oid *old_id, 1279 const char *old_target) 1280{ 1281 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1282 git_filebuf file = GIT_FILEBUF_INIT; 1283 int error = 0; 1284 1285 assert(backend); 1286 1287 if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0) 1288 return error; 1289 1290 /* We need to perform the reflog append and old value check under the ref's lock */ 1291 if ((error = loose_lock(&file, backend, ref->name)) < 0) 1292 return error; 1293 1294 return refdb_fs_backend__write_tail(_backend, ref, &file, true, old_id, old_target, who, message); 1295} 1296 1297static int refdb_fs_backend__write_tail( 1298 git_refdb_backend *_backend, 1299 const git_reference *ref, 1300 git_filebuf *file, 1301 int update_reflog, 1302 const git_oid *old_id, 1303 const char *old_target, 1304 const git_signature *who, 1305 const char *message) 1306{ 1307 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1308 int error = 0, cmp = 0, should_write; 1309 const char *new_target = NULL; 1310 const git_oid *new_id = NULL; 1311 1312 if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0) 1313 goto on_error; 1314 1315 if (cmp) { 1316 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match"); 1317 error = GIT_EMODIFIED; 1318 goto on_error; 1319 } 1320 1321 if (ref->type == GIT_REFERENCE_SYMBOLIC) 1322 new_target = ref->target.symbolic; 1323 else 1324 new_id = &ref->target.oid; 1325 1326 error = cmp_old_ref(&cmp, _backend, ref->name, new_id, new_target); 1327 if (error < 0 && error != GIT_ENOTFOUND) 1328 goto on_error; 1329 1330 /* Don't update if we have the same value */ 1331 if (!error && !cmp) { 1332 error = 0; 1333 goto on_error; /* not really error */ 1334 } 1335 1336 if (update_reflog) { 1337 if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0) 1338 goto on_error; 1339 1340 if (should_write) { 1341 if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0) 1342 goto on_error; 1343 if ((error = maybe_append_head(backend, ref, who, message)) < 0) 1344 goto on_error; 1345 } 1346 } 1347 1348 return loose_commit(file, ref); 1349 1350on_error: 1351 git_filebuf_cleanup(file); 1352 return error; 1353} 1354 1355static void refdb_fs_backend__prune_refs( 1356 refdb_fs_backend *backend, 1357 const char *ref_name, 1358 const char *prefix) 1359{ 1360 git_buf relative_path = GIT_BUF_INIT; 1361 git_buf base_path = GIT_BUF_INIT; 1362 size_t commonlen; 1363 1364 assert(backend && ref_name); 1365 1366 if (git_buf_sets(&relative_path, ref_name) < 0) 1367 goto cleanup; 1368 1369 git_path_squash_slashes(&relative_path); 1370 if ((commonlen = git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path))) == strlen("refs/heads/") || 1371 (commonlen = git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path))) == strlen("refs/tags/") || 1372 (commonlen = git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path))) == strlen("refs/remotes/")) { 1373 1374 git_buf_truncate(&relative_path, commonlen); 1375 1376 if (prefix) { 1377 if (git_buf_join3(&base_path, '/', backend->commonpath, prefix, git_buf_cstr(&relative_path)) < 0) 1378 goto cleanup; 1379 } else { 1380 if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0) 1381 goto cleanup; 1382 } 1383 1384 git_futils_rmdir_r(ref_name + commonlen, git_buf_cstr(&base_path), GIT_RMDIR_EMPTY_PARENTS | GIT_RMDIR_SKIP_ROOT); 1385 } 1386 1387cleanup: 1388 git_buf_dispose(&relative_path); 1389 git_buf_dispose(&base_path); 1390} 1391 1392static int refdb_fs_backend__delete( 1393 git_refdb_backend *_backend, 1394 const char *ref_name, 1395 const git_oid *old_id, const char *old_target) 1396{ 1397 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1398 git_filebuf file = GIT_FILEBUF_INIT; 1399 int error = 0; 1400 1401 assert(backend && ref_name); 1402 1403 if ((error = loose_lock(&file, backend, ref_name)) < 0) 1404 return error; 1405 1406 if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) { 1407 git_filebuf_cleanup(&file); 1408 return error; 1409 } 1410 1411 return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target); 1412} 1413 1414static int loose_delete(refdb_fs_backend *backend, const char *ref_name) 1415{ 1416 git_buf loose_path = GIT_BUF_INIT; 1417 int error = 0; 1418 1419 if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0) 1420 return -1; 1421 1422 error = p_unlink(loose_path.ptr); 1423 if (error < 0 && errno == ENOENT) 1424 error = GIT_ENOTFOUND; 1425 else if (error != 0) 1426 error = -1; 1427 1428 git_buf_dispose(&loose_path); 1429 1430 return error; 1431} 1432 1433static int refdb_fs_backend__delete_tail( 1434 git_refdb_backend *_backend, 1435 git_filebuf *file, 1436 const char *ref_name, 1437 const git_oid *old_id, const char *old_target) 1438{ 1439 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1440 int error = 0, cmp = 0; 1441 bool packed_deleted = 0; 1442 1443 error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target); 1444 if (error < 0) 1445 goto cleanup; 1446 1447 if (cmp) { 1448 git_error_set(GIT_ERROR_REFERENCE, "old reference value does not match"); 1449 error = GIT_EMODIFIED; 1450 goto cleanup; 1451 } 1452 1453 /* 1454 * To ensure that an external observer will see either the current ref value 1455 * (because the loose ref still exists), or a missing ref (after the packed-file is 1456 * unlocked, there will be nothing left), we must ensure things happen in the 1457 * following order: 1458 * 1459 * - the packed-ref file is locked and loaded, as well as a loose one, if it exists 1460 * - we optimistically delete a packed ref, keeping track of whether it existed 1461 * - we delete the loose ref, note that we have its .lock 1462 * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked 1463 * - we should prune the path components if a loose ref was deleted 1464 * 1465 * Note that, because our packed backend doesn't expose its filesystem lock, 1466 * we might not be able to guarantee that this is what actually happens (ie. 1467 * as our current code never write packed-refs.lock, nothing stops observers 1468 * from grabbing a "stale" value from there). 1469 */ 1470 if ((error = packed_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND) 1471 goto cleanup; 1472 1473 if (error == 0) 1474 packed_deleted = 1; 1475 1476 if ((error = loose_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND) 1477 goto cleanup; 1478 1479 if (error == GIT_ENOTFOUND) { 1480 error = packed_deleted ? 0 : ref_error_notfound(ref_name); 1481 goto cleanup; 1482 } 1483 1484cleanup: 1485 git_filebuf_cleanup(file); 1486 if (error == 0) 1487 refdb_fs_backend__prune_refs(backend, ref_name, ""); 1488 return error; 1489} 1490 1491static int refdb_reflog_fs__rename(git_refdb_backend *_backend, const char *old_name, const char *new_name); 1492 1493static int refdb_fs_backend__rename( 1494 git_reference **out, 1495 git_refdb_backend *_backend, 1496 const char *old_name, 1497 const char *new_name, 1498 int force, 1499 const git_signature *who, 1500 const char *message) 1501{ 1502 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1503 git_reference *old, *new = NULL; 1504 git_filebuf file = GIT_FILEBUF_INIT; 1505 int error; 1506 1507 assert(backend); 1508 1509 if ((error = reference_path_available( 1510 backend, new_name, old_name, force)) < 0 || 1511 (error = refdb_fs_backend__lookup(&old, _backend, old_name)) < 0) 1512 return error; 1513 1514 if ((error = refdb_fs_backend__delete(_backend, old_name, NULL, NULL)) < 0) { 1515 git_reference_free(old); 1516 return error; 1517 } 1518 1519 new = git_reference__realloc(&old, new_name); 1520 if (!new) { 1521 git_reference_free(old); 1522 return -1; 1523 } 1524 1525 if ((error = loose_lock(&file, backend, new->name)) < 0) { 1526 git_reference_free(new); 1527 return error; 1528 } 1529 1530 /* Try to rename the refog; it's ok if the old doesn't exist */ 1531 error = refdb_reflog_fs__rename(_backend, old_name, new_name); 1532 if (((error == 0) || (error == GIT_ENOTFOUND)) && 1533 ((error = reflog_append(backend, new, git_reference_target(new), NULL, who, message)) < 0)) { 1534 git_reference_free(new); 1535 git_filebuf_cleanup(&file); 1536 return error; 1537 } 1538 1539 if (error < 0) { 1540 git_reference_free(new); 1541 git_filebuf_cleanup(&file); 1542 return error; 1543 } 1544 1545 1546 if ((error = loose_commit(&file, new)) < 0 || out == NULL) { 1547 git_reference_free(new); 1548 return error; 1549 } 1550 1551 *out = new; 1552 return 0; 1553} 1554 1555static int refdb_fs_backend__compress(git_refdb_backend *_backend) 1556{ 1557 int error; 1558 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1559 1560 assert(backend); 1561 1562 if ((error = packed_reload(backend)) < 0 || /* load the existing packfile */ 1563 (error = packed_loadloose(backend)) < 0 || /* add all the loose refs */ 1564 (error = packed_write(backend)) < 0) /* write back to disk */ 1565 return error; 1566 1567 return 0; 1568} 1569 1570static void refdb_fs_backend__free(git_refdb_backend *_backend) 1571{ 1572 refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1573 1574 assert(backend); 1575 1576 git_sortedcache_free(backend->refcache); 1577 git__free(backend->gitpath); 1578 git__free(backend->commonpath); 1579 git__free(backend); 1580} 1581 1582static char *setup_namespace(git_repository *repo, const char *in) 1583{ 1584 git_buf path = GIT_BUF_INIT; 1585 char *parts, *start, *end, *out = NULL; 1586 1587 if (!in) 1588 goto done; 1589 1590 git_buf_puts(&path, in); 1591 1592 /* if the repo is not namespaced, nothing else to do */ 1593 if (repo->namespace == NULL) { 1594 out = git_buf_detach(&path); 1595 goto done; 1596 } 1597 1598 parts = end = git__strdup(repo->namespace); 1599 if (parts == NULL) 1600 goto done; 1601 1602 /* 1603 * From `man gitnamespaces`: 1604 * namespaces which include a / will expand to a hierarchy 1605 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store 1606 * refs under refs/namespaces/foo/refs/namespaces/bar/ 1607 */ 1608 while ((start = git__strsep(&end, "/")) != NULL) 1609 git_buf_printf(&path, "refs/namespaces/%s/", start); 1610 1611 git_buf_printf(&path, "refs/namespaces/%s/refs", end); 1612 git__free(parts); 1613 1614 /* Make sure that the folder with the namespace exists */ 1615 if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777, 1616 GIT_MKDIR_PATH, NULL) < 0) 1617 goto done; 1618 1619 /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */ 1620 git_buf_rtruncate_at_char(&path, '/'); 1621 out = git_buf_detach(&path); 1622 1623done: 1624 git_buf_dispose(&path); 1625 return out; 1626} 1627 1628static int reflog_alloc(git_reflog **reflog, const char *name) 1629{ 1630 git_reflog *log; 1631 1632 *reflog = NULL; 1633 1634 log = git__calloc(1, sizeof(git_reflog)); 1635 GIT_ERROR_CHECK_ALLOC(log); 1636 1637 log->ref_name = git__strdup(name); 1638 GIT_ERROR_CHECK_ALLOC(log->ref_name); 1639 1640 if (git_vector_init(&log->entries, 0, NULL) < 0) { 1641 git__free(log->ref_name); 1642 git__free(log); 1643 return -1; 1644 } 1645 1646 *reflog = log; 1647 1648 return 0; 1649} 1650 1651static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size) 1652{ 1653 git_parse_ctx parser = GIT_PARSE_CTX_INIT; 1654 1655 if ((git_parse_ctx_init(&parser, buf, buf_size)) < 0) 1656 return -1; 1657 1658 for (; parser.remain_len; git_parse_advance_line(&parser)) { 1659 git_reflog_entry *entry; 1660 const char *sig; 1661 char c; 1662 1663 entry = git__calloc(1, sizeof(*entry)); 1664 GIT_ERROR_CHECK_ALLOC(entry); 1665 entry->committer = git__calloc(1, sizeof(*entry->committer)); 1666 GIT_ERROR_CHECK_ALLOC(entry->committer); 1667 1668 if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 || 1669 git_parse_advance_expected(&parser, " ", 1) < 0 || 1670 git_parse_advance_oid(&entry->oid_cur, &parser) < 0) 1671 goto next; 1672 1673 sig = parser.line; 1674 while (git_parse_peek(&c, &parser, 0) == 0 && c != '\t' && c != '\n') 1675 git_parse_advance_chars(&parser, 1); 1676 1677 if (git_signature__parse(entry->committer, &sig, parser.line, NULL, 0) < 0) 1678 goto next; 1679 1680 if (c == '\t') { 1681 size_t len; 1682 git_parse_advance_chars(&parser, 1); 1683 1684 len = parser.line_len; 1685 if (parser.line[len - 1] == '\n') 1686 len--; 1687 1688 entry->msg = git__strndup(parser.line, len); 1689 GIT_ERROR_CHECK_ALLOC(entry->msg); 1690 } 1691 1692 if ((git_vector_insert(&log->entries, entry)) < 0) { 1693 git_reflog_entry__free(entry); 1694 return -1; 1695 } 1696 1697 continue; 1698 1699next: 1700 git_reflog_entry__free(entry); 1701 } 1702 1703 return 0; 1704} 1705 1706static int create_new_reflog_file(const char *filepath) 1707{ 1708 int fd, error; 1709 1710 if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0) 1711 return error; 1712 1713 if ((fd = p_open(filepath, 1714 O_WRONLY | O_CREAT, 1715 GIT_REFLOG_FILE_MODE)) < 0) 1716 return -1; 1717 1718 return p_close(fd); 1719} 1720 1721GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name) 1722{ 1723 if (strcmp(name, GIT_HEAD_FILE) == 0) 1724 return git_buf_join3(path, '/', repo->gitdir, GIT_REFLOG_DIR, name); 1725 return git_buf_join3(path, '/', repo->commondir, GIT_REFLOG_DIR, name); 1726} 1727 1728static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name) 1729{ 1730 refdb_fs_backend *backend; 1731 git_repository *repo; 1732 git_buf path = GIT_BUF_INIT; 1733 int error; 1734 1735 assert(_backend && name); 1736 1737 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1738 repo = backend->repo; 1739 1740 if ((error = retrieve_reflog_path(&path, repo, name)) < 0) 1741 return error; 1742 1743 error = create_new_reflog_file(git_buf_cstr(&path)); 1744 git_buf_dispose(&path); 1745 1746 return error; 1747} 1748 1749static int has_reflog(git_repository *repo, const char *name) 1750{ 1751 int ret = 0; 1752 git_buf path = GIT_BUF_INIT; 1753 1754 if (retrieve_reflog_path(&path, repo, name) < 0) 1755 goto cleanup; 1756 1757 ret = git_path_isfile(git_buf_cstr(&path)); 1758 1759cleanup: 1760 git_buf_dispose(&path); 1761 return ret; 1762} 1763 1764static int refdb_reflog_fs__has_log(git_refdb_backend *_backend, const char *name) 1765{ 1766 refdb_fs_backend *backend; 1767 1768 assert(_backend && name); 1769 1770 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1771 1772 return has_reflog(backend->repo, name); 1773} 1774 1775static int refdb_reflog_fs__read(git_reflog **out, git_refdb_backend *_backend, const char *name) 1776{ 1777 int error = -1; 1778 git_buf log_path = GIT_BUF_INIT; 1779 git_buf log_file = GIT_BUF_INIT; 1780 git_reflog *log = NULL; 1781 git_repository *repo; 1782 refdb_fs_backend *backend; 1783 1784 assert(out && _backend && name); 1785 1786 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1787 repo = backend->repo; 1788 1789 if (reflog_alloc(&log, name) < 0) 1790 return -1; 1791 1792 if (retrieve_reflog_path(&log_path, repo, name) < 0) 1793 goto cleanup; 1794 1795 error = git_futils_readbuffer(&log_file, git_buf_cstr(&log_path)); 1796 if (error < 0 && error != GIT_ENOTFOUND) 1797 goto cleanup; 1798 1799 if ((error == GIT_ENOTFOUND) && 1800 ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0)) 1801 goto cleanup; 1802 1803 if ((error = reflog_parse(log, 1804 git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0) 1805 goto cleanup; 1806 1807 *out = log; 1808 goto success; 1809 1810cleanup: 1811 git_reflog_free(log); 1812 1813success: 1814 git_buf_dispose(&log_file); 1815 git_buf_dispose(&log_path); 1816 1817 return error; 1818} 1819 1820static int serialize_reflog_entry( 1821 git_buf *buf, 1822 const git_oid *oid_old, 1823 const git_oid *oid_new, 1824 const git_signature *committer, 1825 const char *msg) 1826{ 1827 char raw_old[GIT_OID_HEXSZ+1]; 1828 char raw_new[GIT_OID_HEXSZ+1]; 1829 1830 git_oid_tostr(raw_old, GIT_OID_HEXSZ+1, oid_old); 1831 git_oid_tostr(raw_new, GIT_OID_HEXSZ+1, oid_new); 1832 1833 git_buf_clear(buf); 1834 1835 git_buf_puts(buf, raw_old); 1836 git_buf_putc(buf, ' '); 1837 git_buf_puts(buf, raw_new); 1838 1839 git_signature__writebuf(buf, " ", committer); 1840 1841 /* drop trailing LF */ 1842 git_buf_rtrim(buf); 1843 1844 if (msg) { 1845 size_t i; 1846 1847 git_buf_putc(buf, '\t'); 1848 git_buf_puts(buf, msg); 1849 1850 for (i = 0; i < buf->size - 2; i++) 1851 if (buf->ptr[i] == '\n') 1852 buf->ptr[i] = ' '; 1853 git_buf_rtrim(buf); 1854 } 1855 1856 git_buf_putc(buf, '\n'); 1857 1858 return git_buf_oom(buf); 1859} 1860 1861static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char *refname) 1862{ 1863 git_repository *repo; 1864 git_buf log_path = GIT_BUF_INIT; 1865 int error; 1866 1867 repo = backend->repo; 1868 1869 if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { 1870 git_error_set(GIT_ERROR_INVALID, "invalid reference name '%s'", refname); 1871 return GIT_EINVALIDSPEC; 1872 } 1873 1874 if (retrieve_reflog_path(&log_path, repo, refname) < 0) 1875 return -1; 1876 1877 if (!git_path_isfile(git_buf_cstr(&log_path))) { 1878 git_error_set(GIT_ERROR_INVALID, 1879 "log file for reference '%s' doesn't exist", refname); 1880 error = -1; 1881 goto cleanup; 1882 } 1883 1884 error = git_filebuf_open(file, git_buf_cstr(&log_path), 0, GIT_REFLOG_FILE_MODE); 1885 1886cleanup: 1887 git_buf_dispose(&log_path); 1888 1889 return error; 1890} 1891 1892static int refdb_reflog_fs__write(git_refdb_backend *_backend, git_reflog *reflog) 1893{ 1894 int error = -1; 1895 unsigned int i; 1896 git_reflog_entry *entry; 1897 refdb_fs_backend *backend; 1898 git_buf log = GIT_BUF_INIT; 1899 git_filebuf fbuf = GIT_FILEBUF_INIT; 1900 1901 assert(_backend && reflog); 1902 1903 backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent); 1904 1905 if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0) 1906 return -1; 1907 1908 git_vector_foreach(&reflog->entries, i, entry) { 1909 if (serialize_reflog_entry(&log, &(entry->oid_old), &(entry->oid_cur), entry->committer, entry->msg) < 0) 1910 goto cleanup; 1911 1912 if ((error = git_filebuf_write(&fbuf, log.ptr, log.size)) < 0) 1913 goto cleanup; 1914 } 1915 1916 error = git_filebuf_commit(&fbuf); 1917 goto success; 1918 1919cleanup: 1920 git_filebuf_cleanup(&fbuf); 1921 1922success: 1923 git_buf_dispose(&log); 1924 1925 return error; 1926} 1927 1928/* Append to the reflog, must be called under reference lock */ 1929static 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) 1930{ 1931 int error, is_symbolic, open_flags; 1932 git_oid old_id = {{0}}, new_id = {{0}}; 1933 git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; 1934 git_repository *repo = backend->repo; 1935 1936 is_symbolic = ref->type == GIT_REFERENCE_SYMBOLIC; 1937 1938 /* "normal" symbolic updates do not write */ 1939 if (is_symbolic && 1940 strcmp(ref->name, GIT_HEAD_FILE) && 1941 !(old && new)) 1942 return 0; 1943 1944 /* From here on is_symbolic also means that it's HEAD */ 1945 1946 if (old) { 1947 git_oid_cpy(&old_id, old); 1948 } else { 1949 error = git_reference_name_to_id(&old_id, repo, ref->name); 1950 if (error < 0 && error != GIT_ENOTFOUND) 1951 return error; 1952 } 1953 1954 if (new) { 1955 git_oid_cpy(&new_id, new); 1956 } else { 1957 if (!is_symbolic) { 1958 git_oid_cpy(&new_id, git_reference_target(ref)); 1959 } else { 1960 error = git_reference_name_to_id(&new_id, repo, git_reference_symbolic_target(ref)); 1961 if (error < 0 && error != GIT_ENOTFOUND) 1962 return error; 1963 /* detaching HEAD does not create an entry */ 1964 if (error == GIT_ENOTFOUND) 1965 return 0; 1966 1967 git_error_clear(); 1968 } 1969 } 1970 1971 if ((error = serialize_reflog_entry(&buf, &old_id, &new_id, who, message)) < 0) 1972 goto cleanup; 1973 1974 if ((error = retrieve_reflog_path(&path, repo, ref->name)) < 0) 1975 goto cleanup; 1976 1977 if (((error = git_futils_mkpath2file(git_buf_cstr(&path), 0777)) < 0) && 1978 (error != GIT_EEXISTS)) { 1979 goto cleanup; 1980 } 1981 1982 /* If the new branch matches part of the namespace of a previously deleted branch, 1983 * there maybe an obsolete/unused directory (or directory hierarchy) in the way. 1984 */ 1985 if (git_path_isdir(git_buf_cstr(&path))) { 1986 if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) { 1987 if (error …
Large files files are truncated, but you can click here to view the full file