Download raw body.
simplify send.c for target refnames
Josh Rickmar <jrick@zettaport.com> wrote: > On Wed, Jul 05, 2023 at 10:40:43AM -0400, Josh Rickmar wrote: > > On Wed, Jul 05, 2023 at 08:38:09AM -0400, Josh Rickmar wrote: > > > got_send_pack in send.c stuffed into a single reflist only to > > > > > > 1) resolve these references multiple times over > > > 2) convert the damn thing to a pathlist in the end because the reflist isn't > > > linked into the privsep handlers. > > > > > > Building the pathlist directly seems like the saner approach. This also > > > moves the validation that the reference is 'sendable' (by got policy rules) > > > to insert_ref. > > > > > > The reference names are now provided directly as an insert_ref > > > parameter instead of getting this from the resolved reference (which > > > we now only do to check that it is not a symlink and is a valid type). > > > This will simplify the cvg patch as it will allow us to put arbitrary > > > target reference names into the pathlist, which correspond to object > > > ids (pe->data). > > > > > > Passes send.sh regress. > > > > Updated with feedback. Also changed their_ids to borrow the object > > ids from their_refs so the cleanup is the same for both arrays. > > tb@ found a leak of the asprintf/strdup if insert_sendable_ref fails. Very nice, thanks! ok for me > diff /home/jrick/src/got > commit - 51b56d129f9e0504bdf70209c1011a5b077742a6 > path + /home/jrick/src/got > blob - 2de21da09b554d15bc73174e05f9df16eaa3e746 > file + lib/send.c > --- lib/send.c > +++ lib/send.c > @@ -1,6 +1,7 @@ > /* > * Copyright (c) 2018, 2019 Ori Bernstein <ori@openbsd.org> > * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org> > + * Copyright (c) 2023 Josh Rickmar <jrick@zettaport.com> > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > @@ -143,21 +144,47 @@ insert_ref(struct got_reflist_head *refs, const char * > } > > static const struct got_error * > -insert_ref(struct got_reflist_head *refs, const char *refname, > +insert_sendable_ref(struct got_pathlist_head *refs, const char *refname, > struct got_repository *repo) > { > const struct got_error *err; > struct got_reference *ref; > - struct got_reflist_entry *new; > + struct got_object_id *id = NULL; > + int obj_type; > > err = got_ref_open(&ref, repo, refname, 0); > if (err) > return err; > > - err = got_reflist_insert(&new, refs, ref, got_ref_cmp_by_name, NULL); > - if (err || new == NULL /* duplicate */) > - got_ref_close(ref); > + if (got_ref_is_symbolic(ref)) { > + err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, > + "cannot send symbolic reference %s", refname); > + goto done; > + } > > + err = got_ref_resolve(&id, repo, ref); > + if (err) > + goto done; > + err = got_object_get_type(&obj_type, repo, id); > + if (err) > + goto done; > + switch (obj_type) { > + case GOT_OBJ_TYPE_COMMIT: > + case GOT_OBJ_TYPE_TAG: > + break; > + default: > + err = got_error_fmt(GOT_ERR_OBJ_TYPE, > + "cannot send %s", refname); > + goto done; > + } > + > + err = got_pathlist_insert(NULL, refs, refname, id); > +done: > + if (err != NULL) { > + if (ref) > + got_ref_close(ref); > + free(id); > + } > return err; > } > > @@ -210,31 +237,14 @@ static struct got_reference * > return NULL; > } > > -static struct got_reference * > -find_ref(struct got_reflist_head *refs, const char *refname) > -{ > - struct got_reflist_entry *re; > - > - TAILQ_FOREACH(re, refs, entry) { > - if (got_path_cmp(got_ref_get_name(re->ref), refname, > - strlen(got_ref_get_name(re->ref)), > - strlen(refname)) == 0) { > - return re->ref; > - } > - } > - > - return NULL; > -} > - > static struct got_pathlist_entry * > -find_their_ref(struct got_pathlist_head *their_refs, const char *refname) > +find_ref(struct got_pathlist_head *refs, const char *refname) > { > struct got_pathlist_entry *pe; > > - TAILQ_FOREACH(pe, their_refs, entry) { > - const char *their_refname = pe->path; > - if (got_path_cmp(their_refname, refname, > - strlen(their_refname), strlen(refname)) == 0) { > + TAILQ_FOREACH(pe, refs, entry) { > + if (got_path_cmp(pe->path, refname, strlen(pe->path), > + strlen(refname)) == 0) { > return pe; > } > } > @@ -259,22 +269,18 @@ update_remote_ref(struct got_reference *my_ref, const > } > > static const struct got_error * > -update_remote_ref(struct got_reference *my_ref, const char *remote_name, > +update_remote_ref(struct got_pathlist_entry *my_ref, const char *remote_name, > struct got_repository *repo) > { > const struct got_error *err, *unlock_err; > - struct got_object_id *my_id; > + const char *refname = my_ref->path; > + struct got_object_id *my_id = my_ref->data; > struct got_reference *ref = NULL; > char *remote_refname = NULL; > int ref_locked = 0; > > - err = got_ref_resolve(&my_id, repo, my_ref); > + err = get_remote_refname(&remote_refname, remote_name, refname); > if (err) > - return err; > - > - err = get_remote_refname(&remote_refname, remote_name, > - got_ref_get_name(my_ref)); > - if (err) > goto done; > > err = got_ref_open(&ref, repo, remote_refname, 1 /* lock */); > @@ -301,7 +307,6 @@ done: > } > got_ref_close(ref); > } > - free(my_id); > free(remote_refname); > return err; > } > @@ -320,14 +325,12 @@ got_send_pack(const char *remote_name, struct got_path > const struct got_error *err; > struct imsgbuf sendibuf; > pid_t sendpid = -1; > - struct got_reflist_head refs; > struct got_pathlist_head have_refs; > struct got_pathlist_head their_refs; > struct got_pathlist_entry *pe; > - struct got_reflist_entry *re; > struct got_object_id **our_ids = NULL; > struct got_object_id **their_ids = NULL; > - int i, nours = 0, ntheirs = 0; > + int nours = 0, ntheirs = 0; > size_t nalloc_ours = 0, nalloc_theirs = 0; > int refs_to_send = 0, refs_to_delete = 0; > off_t bytes_sent = 0, bytes_sent_cur = 0; > @@ -335,37 +338,39 @@ got_send_pack(const char *remote_name, struct got_path > uint8_t packsha1[SHA1_DIGEST_LENGTH]; > int packfd = -1; > FILE *delta_cache = NULL; > + char *s = NULL; > > - TAILQ_INIT(&refs); > TAILQ_INIT(&have_refs); > TAILQ_INIT(&their_refs); > > TAILQ_FOREACH(pe, branch_names, entry) { > const char *branchname = pe->path; > if (strncmp(branchname, "refs/heads/", 11) != 0) { > - char *s; > if (asprintf(&s, "refs/heads/%s", branchname) == -1) { > err = got_error_from_errno("asprintf"); > goto done; > } > - err = insert_ref(&refs, s, repo); > - free(s); > } else { > - err = insert_ref(&refs, branchname, repo); > + if ((s = strdup(branchname)) == NULL) { > + err = got_error_from_errno("strdup"); > + goto done; > + } > } > + err = insert_sendable_ref(&have_refs, s, repo); > if (err) > goto done; > + s = NULL; > } > > TAILQ_FOREACH(pe, delete_branches, entry) { > const char *branchname = pe->path; > - struct got_reference *ref; > + struct got_pathlist_entry *ref; > if (strncmp(branchname, "refs/heads/", 11) != 0) { > err = got_error_fmt(GOT_ERR_SEND_DELETE_REF, "%s", > branchname); > goto done; > } > - ref = find_ref(&refs, branchname); > + ref = find_ref(&have_refs, branchname); > if (ref) { > err = got_error_fmt(GOT_ERR_SEND_DELETE_REF, > "changes on %s will be sent to server", > @@ -377,54 +382,27 @@ got_send_pack(const char *remote_name, struct got_path > TAILQ_FOREACH(pe, tag_names, entry) { > const char *tagname = pe->path; > if (strncmp(tagname, "refs/tags/", 10) != 0) { > - char *s; > if (asprintf(&s, "refs/tags/%s", tagname) == -1) { > err = got_error_from_errno("asprintf"); > goto done; > } > - err = insert_ref(&refs, s, repo); > - free(s); > } else { > - err = insert_ref(&refs, tagname, repo); > + if ((s = strdup(pe->path)) == NULL) { > + err = got_error_from_errno("strdup"); > + goto done; > + } > } > + err = insert_sendable_ref(&have_refs, s, repo); > if (err) > goto done; > + s = NULL; > } > > - if (TAILQ_EMPTY(&refs) && TAILQ_EMPTY(delete_branches)) { > + if (TAILQ_EMPTY(&have_refs) && TAILQ_EMPTY(delete_branches)) { > err = got_error(GOT_ERR_SEND_EMPTY); > goto done; > } > > - TAILQ_FOREACH(re, &refs, entry) { > - struct got_object_id *id; > - int obj_type; > - > - if (got_ref_is_symbolic(re->ref)) { > - err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, > - "cannot send symbolic reference %s", > - got_ref_get_name(re->ref)); > - goto done; > - } > - > - err = got_ref_resolve(&id, repo, re->ref); > - if (err) > - goto done; > - err = got_object_get_type(&obj_type, repo, id); > - free(id); > - if (err) > - goto done; > - switch (obj_type) { > - case GOT_OBJ_TYPE_COMMIT: > - case GOT_OBJ_TYPE_TAG: > - break; > - default: > - err = got_error_fmt(GOT_ERR_OBJ_TYPE, > - "cannot send %s", got_ref_get_name(re->ref)); > - goto done; > - } > - } > - > packfd = got_opentempfd(); > if (packfd == -1) { > err = got_error_from_errno("got_opentempfd"); > @@ -463,22 +441,12 @@ got_send_pack(const char *remote_name, struct got_path > } > > /* > - * Convert reflist to pathlist since the privsep layer > - * is linked into helper programs which lack reference.c. > + * Also prepare the array of our object IDs which > + * will be needed for generating a pack file. > */ > - TAILQ_FOREACH(re, &refs, entry) { > - struct got_object_id *id; > - err = got_ref_resolve(&id, repo, re->ref); > - if (err) > - goto done; > - err = got_pathlist_append(&have_refs, > - got_ref_get_name(re->ref), id); > - if (err) > - goto done; > - /* > - * Also prepare the array of our object IDs which > - * will be needed for generating a pack file. > - */ > + TAILQ_FOREACH(pe, &have_refs, entry) { > + struct got_object_id *id = pe->data; > + > err = realloc_ids(&our_ids, &nalloc_ours, nours + 1); > if (err) > goto done; > @@ -507,7 +475,7 @@ got_send_pack(const char *remote_name, struct got_path > struct got_object_id *their_id = pe->data; > int have_their_id; > struct got_object *obj; > - struct got_reference *my_ref = NULL; > + struct got_pathlist_entry *my_ref = NULL; > int is_tag = 0; > > /* Don't blindly trust the server to send us valid names. */ > @@ -521,23 +489,18 @@ got_send_pack(const char *remote_name, struct got_path > * Otherwise we can still use this reference as a hint to > * avoid uploading any objects the server already has. > */ > - my_ref = find_ref(&refs, refname); > + my_ref = find_ref(&have_refs, refname); > if (my_ref) { > - struct got_object_id *my_id; > - err = got_ref_resolve(&my_id, repo, my_ref); > - if (err) > - goto done; > + struct got_object_id *my_id = my_ref->data; > if (got_object_id_cmp(my_id, their_id) != 0) { > if (!overwrite_refs && is_tag) { > err = got_error_fmt( > GOT_ERR_SEND_TAG_EXISTS, > "%s", refname); > - free(my_id); > goto done; > } > refs_to_send++; > } > - free(my_id); > } > > /* Check if their object exists locally. */ > @@ -563,23 +526,14 @@ got_send_pack(const char *remote_name, struct got_path > if (have_their_id) { > /* Enforce linear ancestry if required. */ > if (!overwrite_refs && my_ref && !is_tag) { > - struct got_object_id *my_id; > - err = got_ref_resolve(&my_id, repo, my_ref); > - if (err) > - goto done; > + struct got_object_id *my_id = my_ref->data; > err = check_common_ancestry(refname, my_id, > their_id, repo, cancel_cb, cancel_arg); > - free(my_id); > - my_id = NULL; > if (err) > goto done; > } > /* Exclude any objects reachable via their ID. */ > - their_ids[ntheirs] = got_object_id_dup(their_id); > - if (their_ids[ntheirs] == NULL) { > - err = got_error_from_errno("got_object_id_dup"); > - goto done; > - } > + their_ids[ntheirs] = their_id; > ntheirs++; > } else if (!is_tag) { > char *remote_refname; > @@ -609,16 +563,16 @@ got_send_pack(const char *remote_name, struct got_path > } > > /* Account for any new references we are going to upload. */ > - TAILQ_FOREACH(re, &refs, entry) { > - if (find_their_ref(&their_refs, > - got_ref_get_name(re->ref)) == NULL) > + TAILQ_FOREACH(pe, &have_refs, entry) { > + const char *refname = pe->path; > + if (find_ref(&their_refs, refname) == NULL) > refs_to_send++; > } > > /* Account for any existing references we are going to delete. */ > TAILQ_FOREACH(pe, delete_branches, entry) { > const char *branchname = pe->path; > - if (find_their_ref(&their_refs, branchname)) > + if (find_ref(&their_refs, branchname)) > refs_to_delete++; > } > > @@ -670,12 +624,12 @@ got_send_pack(const char *remote_name, struct got_path > goto done; > if (refname && got_ref_name_is_valid(refname) && success && > strncmp(refname, "refs/tags/", 10) != 0) { > - struct got_reference *my_ref; > + struct got_pathlist_entry *my_ref; > /* > * The server has accepted our changes. > * Update our reference in refs/remotes/ accordingly. > */ > - my_ref = find_ref(&refs, refname); > + my_ref = find_ref(&have_refs, refname); > if (my_ref) { > err = update_remote_ref(my_ref, remote_name, > repo); > @@ -716,14 +670,14 @@ done: > if (npackfd != -1 && close(npackfd) == -1 && err == NULL) > err = got_error_from_errno("close"); > > - got_ref_list_free(&refs); > - got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_NONE); > - got_pathlist_free(&their_refs, GOT_PATHLIST_FREE_NONE); > - for (i = 0; i < nours; i++) > - free(our_ids[i]); > + got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL); > + got_pathlist_free(&their_refs, GOT_PATHLIST_FREE_ALL); > + /* > + * Object ids are owned by have_refs/their_refs and are already freed; > + * Only the arrays must be freed. > + */ > free(our_ids); > - for (i = 0; i < ntheirs; i++) > - free(their_ids[i]); > free(their_ids); > + free(s); > return err; > } -- Mark Jamsek <https://bsdbox.org> GPG: F2FF 13DE 6A06 C471 CA80 E6E2 2930 DC66 86EE CF68
simplify send.c for target refnames