git-2.22.0/refs/packed-backend.c
/*
 * Write the packed refs from the current snapshot to the packed-refs
 * tempfile, incorporating any changes from `updates`. `updates` must
 * be a sorted string list whose keys are the refnames and whose util
 * values are `struct ref_update *`. On error, rollback the tempfile,
 * write an error message to `err`, and return a nonzero value.
 *
 * The packfile must be locked before calling this function and will
 * remain locked when it is done.
 */
Write the packed refs from the current snapshot to the packed-refs
tempfile, incorporating any changes from `updates`. `updates` must
be a sorted string list whose keys are the refnames and whose util
values are `struct ref_update *`. On error, rollback the tempfile,
write an error message to `err`, and return a nonzero value.

The packfile must be locked before calling this function and will
remain locked when it is done.
Write the packed refs from the current snapshot to the packed - refs tempfile incorporating any changes from ` updates ` . ` updates ` must be a sorted string list whose keys are the refnames and whose util values are ` struct ref_update * ` . On error rollback the tempfile write an error message to ` err ` and return a nonzero value . The packfile must be locked before calling this function and will remain locked when it is done .
static int write_with_updates(struct packed_ref_store *refs,
			      struct string_list *updates,
			      struct strbuf *err)
{
	struct ref_iterator *iter = NULL;
	size_t i;
	int ok;
	FILE *out;
	struct strbuf sb = STRBUF_INIT;
	char *packed_refs_path;
	if (!is_lock_file_locked(&refs->lock))
		BUG("write_with_updates() called while unlocked");
	packed_refs_path = get_locked_file_path(&refs->lock);
	strbuf_addf(&sb, "%s.new", packed_refs_path);
	free(packed_refs_path);
	refs->tempfile = create_tempfile(sb.buf);
	if (!refs->tempfile) {
		strbuf_addf(err, "unable to create file %s: %s",
			    sb.buf, strerror(errno));
		strbuf_release(&sb);
		return -1;
	}
	strbuf_release(&sb);
	out = fdopen_tempfile(refs->tempfile, "w");
	if (!out) {
		strbuf_addf(err, "unable to fdopen packed-refs tempfile: %s",
			    strerror(errno));
		goto error;
	}
	if (fprintf(out, "%s", PACKED_REFS_HEADER) < 0)
		goto write_error;
	iter = packed_ref_iterator_begin(&refs->base, "",
					 DO_FOR_EACH_INCLUDE_BROKEN);
	if ((ok = ref_iterator_advance(iter)) != ITER_OK)
		iter = NULL;
	i = 0;
	while (iter || i < updates->nr) {
		struct ref_update *update = NULL;
		int cmp;
		if (i >= updates->nr) {
			cmp = -1;
		} else {
			update = updates->items[i].util;
			if (!iter)
				cmp = +1;
			else
				cmp = strcmp(iter->refname, update->refname);
		}
		if (!cmp) {
			if ((update->flags & REF_HAVE_OLD)) {
				if (is_null_oid(&update->old_oid)) {
					strbuf_addf(err, "cannot update ref '%s': "
						    "reference already exists",
						    update->refname);
					goto error;
				} else if (!oideq(&update->old_oid, iter->oid)) {
					strbuf_addf(err, "cannot update ref '%s': "
						    "is at %s but expected %s",
						    update->refname,
						    oid_to_hex(iter->oid),
						    oid_to_hex(&update->old_oid));
					goto error;
				}
			}
			if ((update->flags & REF_HAVE_NEW)) {
				if ((ok = ref_iterator_advance(iter)) != ITER_OK)
					iter = NULL;
				cmp = +1;
			} else {
				i++;
				cmp = -1;
			}
		} else if (cmp > 0) {
			if ((update->flags & REF_HAVE_OLD) &&
			    !is_null_oid(&update->old_oid)) {
				strbuf_addf(err, "cannot update ref '%s': "
					    "reference is missing but expected %s",
					    update->refname,
					    oid_to_hex(&update->old_oid));
				goto error;
			}
		}
		if (cmp < 0) {
			struct object_id peeled;
			int peel_error = ref_iterator_peel(iter, &peeled);
			if (write_packed_entry(out, iter->refname,
					       iter->oid,
					       peel_error ? NULL : &peeled))
				goto write_error;
			if ((ok = ref_iterator_advance(iter)) != ITER_OK)
				iter = NULL;
		} else if (is_null_oid(&update->new_oid)) {
			i++;
		} else {
			struct object_id peeled;
			int peel_error = peel_object(&update->new_oid,
						     &peeled);
			if (write_packed_entry(out, update->refname,
					       &update->new_oid,
					       peel_error ? NULL : &peeled))
				goto write_error;
			i++;
		}
	}
	if (ok != ITER_DONE) {
		strbuf_addstr(err, "unable to write packed-refs file: "
			      "error iterating over old contents");
		goto error;
	}
	if (close_tempfile_gently(refs->tempfile)) {
		strbuf_addf(err, "error closing file %s: %s",
			    get_tempfile_path(refs->tempfile),
			    strerror(errno));
		strbuf_release(&sb);
		delete_tempfile(&refs->tempfile);
		return -1;
	}
	return 0;
write_error:
	strbuf_addf(err, "error writing to %s: %s",
		    get_tempfile_path(refs->tempfile), strerror(errno));
error:
	if (iter)
		ref_iterator_abort(iter);
	delete_tempfile(&refs->tempfile);
	return -1;
}
static int write_with_updates ( struct packed_ref_store * refs , struct string_list * updates , struct strbuf * err ) { struct ref_iterator * iter = NULL ; size_t i ; int ok ; FILE * out ; struct strbuf sb = STRBUF_INIT ; char * packed_refs_path ; if ( ! is_lock_file_locked ( & refs -> lock ) ) BUG ( " " ) ; packed_refs_path = get_locked_file_path ( & refs -> lock ) ; strbuf_addf ( & sb , " " , packed_refs_path ) ; free ( packed_refs_path ) ; refs -> tempfile = create_tempfile ( sb . buf ) ; if ( ! refs -> tempfile ) { strbuf_addf ( err , " " , sb . buf , strerror ( errno ) ) ; strbuf_release ( & sb ) ; return -1 ; } strbuf_release ( & sb ) ; out = fdopen_tempfile ( refs -> tempfile , " " ) ; if ( ! out ) { strbuf_addf ( err , " " , strerror ( errno ) ) ; goto error ; } if ( fprintf ( out , " " , PACKED_REFS_HEADER ) < 0 ) goto write_error ; iter = packed_ref_iterator_begin ( & refs -> base , " " , DO_FOR_EACH_INCLUDE_BROKEN ) ; if ( ( ok = ref_iterator_advance ( iter ) ) != ITER_OK ) iter = NULL ; i = 0 ; while ( iter || i < updates -> nr ) { struct ref_update * update = NULL ; int cmp ; if ( i >= updates -> nr ) { cmp = -1 ; } else { update = updates -> items [ i ] . util ; if ( ! iter ) cmp = +1 ; else cmp = strcmp ( iter -> refname , update -> refname ) ; } if ( ! cmp ) { if ( ( update -> flags & REF_HAVE_OLD ) ) { if ( is_null_oid ( & update -> old_oid ) ) { strbuf_addf ( err , " " " " , update -> refname ) ; goto error ; } else if ( ! oideq ( & update -> old_oid , iter -> oid ) ) { strbuf_addf ( err , " " " " , update -> refname , oid_to_hex ( iter -> oid ) , oid_to_hex ( & update -> old_oid ) ) ; goto error ; } } if ( ( update -> flags & REF_HAVE_NEW ) ) { if ( ( ok = ref_iterator_advance ( iter ) ) != ITER_OK ) iter = NULL ; cmp = +1 ; } else { i ++ ; cmp = -1 ; } } else if ( cmp > 0 ) { if ( ( update -> flags & REF_HAVE_OLD ) && ! is_null_oid ( & update -> old_oid ) ) { strbuf_addf ( err , " " " " , update -> refname , oid_to_hex ( & update -> old_oid ) ) ; goto error ; } } if ( cmp < 0 ) { struct object_id peeled ; int peel_error = ref_iterator_peel ( iter , & peeled ) ; if ( write_packed_entry ( out , iter -> refname , iter -> oid , peel_error ? NULL : & peeled ) ) goto write_error ; if ( ( ok = ref_iterator_advance ( iter ) ) != ITER_OK ) iter = NULL ; } else if ( is_null_oid ( & update -> new_oid ) ) { i ++ ; } else { struct object_id peeled ; int peel_error = peel_object ( & update -> new_oid , & peeled ) ; if ( write_packed_entry ( out , update -> refname , & update -> new_oid , peel_error ? NULL : & peeled ) ) goto write_error ; i ++ ; } } if ( ok != ITER_DONE ) { strbuf_addstr ( err , " " " " ) ; goto error ; } if ( close_tempfile_gently ( refs -> tempfile ) ) { strbuf_addf ( err , " " , get_tempfile_path ( refs -> tempfile ) , strerror ( errno ) ) ; strbuf_release ( & sb ) ; delete_tempfile ( & refs -> tempfile ) ; return -1 ; } return 0 ; write_error : strbuf_addf ( err , " " , get_tempfile_path ( refs -> tempfile ) , strerror ( errno ) ) ; error : if ( iter ) ref_iterator_abort ( iter ) ; delete_tempfile ( & refs -> tempfile ) ; return -1 ; }
Write the packed refs from the current snapshot to the packed-refs
 tempfile, incorporating any changes from `updates`.
Write the packed refs from the current snapshot to the packed - refs tempfile incorporating any changes from ` updates ` .
/*
	 * If packed-refs is a symlink, we want to overwrite the
	 * symlinked-to file, not the symlink itself. Also, put the
	 * staging file next to it:
	 */ /*
	 * We iterate in parallel through the current list of refs and
	 * the list of updates, processing an entry from at least one
	 * of the lists each time through the loop. When the current
	 * list of refs is exhausted, set iter to NULL. When the list
	 * of updates is exhausted, leave i set to updates->nr.
	 */ /*
			 * There is both an old value and an update
			 * for this reference. Check the old value if
			 * necessary:
			 */ /* Now figure out what to use for the new value: */ /*
				 * The update takes precedence. Skip
				 * the iterator over the unneeded
				 * value.
				 */ /*
				 * The update doesn't actually want to
				 * change anything. We're done with it.
				 */ /*
			 * There is no old value but there is an
			 * update for this reference. Make sure that
			 * the update didn't expect an existing value:
			 */ /* Pass the old reference through. */ /*
			 * The update wants to delete the reference,
			 * and the reference either didn't exist or we
			 * have already skipped it. So we're done with
			 * the update (and don't have to write
			 * anything).
			 */