]> git.proxmox.com Git - libgit2.git/blame - src/notes.c
New upstream version 1.0.0+dfsg.1
[libgit2.git] / src / notes.c
CommitLineData
bf477ed4 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
bf477ed4
MS
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 "notes.h"
9
10#include "git2.h"
11#include "refs.h"
caea5e54 12#include "config.h"
86ecd844 13#include "iterator.h"
4ec197f3 14#include "signature.h"
ac3d33df 15#include "blob.h"
bf477ed4 16
734c6fc1
RB
17static int note_error_notfound(void)
18{
ac3d33df 19 git_error_set(GIT_ERROR_INVALID, "note could not be found");
734c6fc1
RB
20 return GIT_ENOTFOUND;
21}
22
b93688d0
VM
23static int find_subtree_in_current_level(
24 git_tree **out,
25 git_repository *repo,
26 git_tree *parent,
27 const char *annotated_object_sha,
28 int fanout)
bf477ed4 29{
e120123e 30 size_t i;
bf477ed4
MS
31 const git_tree_entry *entry;
32
a02e7249 33 *out = NULL;
e120123e 34
a02e7249 35 if (parent == NULL)
734c6fc1 36 return note_error_notfound();
bf477ed4 37
a02e7249 38 for (i = 0; i < git_tree_entrycount(parent); i++) {
39 entry = git_tree_entry_byindex(parent, i);
bf477ed4
MS
40
41 if (!git__ishex(git_tree_entry_name(entry)))
42 continue;
43
9d7ac675 44 if (S_ISDIR(git_tree_entry_filemode(entry))
e120123e 45 && strlen(git_tree_entry_name(entry)) == 2
a02e7249 46 && !strncmp(git_tree_entry_name(entry), annotated_object_sha + fanout, 2))
47 return git_tree_lookup(out, repo, git_tree_entry_id(entry));
bf477ed4 48
a02e7249 49 /* Not a DIR, so do we have an already existing blob? */
e120123e 50 if (!strcmp(git_tree_entry_name(entry), annotated_object_sha + fanout))
a02e7249 51 return GIT_EEXISTS;
52 }
bf477ed4 53
734c6fc1 54 return note_error_notfound();
a02e7249 55}
bf477ed4 56
a02e7249 57static int find_subtree_r(git_tree **out, git_tree *root,
58 git_repository *repo, const char *target, int *fanout)
59{
60 int error;
61 git_tree *subtree = NULL;
bf477ed4 62
a02e7249 63 *out = NULL;
bf477ed4 64
a02e7249 65 error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout);
734c6fc1 66 if (error == GIT_EEXISTS)
dca6b228 67 return git_tree_lookup(out, repo, git_tree_id(root));
bf477ed4 68
a02e7249 69 if (error < 0)
b93688d0 70 return error;
a02e7249 71
72 *fanout += 2;
73 error = find_subtree_r(out, subtree, repo, target, fanout);
dca6b228 74 git_tree_free(subtree);
a02e7249 75
a02e7249 76 return error;
bf477ed4
MS
77}
78
79static int find_blob(git_oid *blob, git_tree *tree, const char *target)
80{
e120123e 81 size_t i;
bf477ed4
MS
82 const git_tree_entry *entry;
83
84 for (i=0; i<git_tree_entrycount(tree); i++) {
85 entry = git_tree_entry_byindex(tree, i);
86
87 if (!strcmp(git_tree_entry_name(entry), target)) {
88 /* found matching note object - return */
89
90 git_oid_cpy(blob, git_tree_entry_id(entry));
4aa7de15 91 return 0;
bf477ed4
MS
92 }
93 }
734c6fc1
RB
94
95 return note_error_notfound();
bf477ed4
MS
96}
97
b93688d0
VM
98static int tree_write(
99 git_tree **out,
100 git_repository *repo,
101 git_tree *source_tree,
102 const git_oid *object_oid,
103 const char *treeentry_name,
104 unsigned int attributes)
bf477ed4 105{
a02e7249 106 int error;
107 git_treebuilder *tb = NULL;
0e2fcca8 108 const git_tree_entry *entry;
a02e7249 109 git_oid tree_oid;
bf477ed4 110
208a2c8a 111 if ((error = git_treebuilder_new(&tb, repo, source_tree)) < 0)
a02e7249 112 goto cleanup;
bf477ed4 113
a02e7249 114 if (object_oid) {
b93688d0
VM
115 if ((error = git_treebuilder_insert(
116 &entry, tb, treeentry_name, object_oid, attributes)) < 0)
a02e7249 117 goto cleanup;
118 } else {
119 if ((error = git_treebuilder_remove(tb, treeentry_name)) < 0)
120 goto cleanup;
121 }
bf477ed4 122
dce7b1a4 123 if ((error = git_treebuilder_write(&tree_oid, tb)) < 0)
a02e7249 124 goto cleanup;
bf477ed4 125
a02e7249 126 error = git_tree_lookup(out, repo, &tree_oid);
bf477ed4 127
a02e7249 128cleanup:
129 git_treebuilder_free(tb);
130 return error;
131}
bf477ed4 132
b93688d0
VM
133static int manipulate_note_in_tree_r(
134 git_tree **out,
135 git_repository *repo,
136 git_tree *parent,
137 git_oid *note_oid,
138 const char *annotated_object_sha,
4a44087a 139 int fanout,
b93688d0 140 int (*note_exists_cb)(
4a44087a
NV
141 git_tree **out,
142 git_repository *repo,
b93688d0
VM
143 git_tree *parent,
144 git_oid *note_oid,
145 const char *annotated_object_sha,
146 int fanout,
147 int current_error),
148 int (*note_notfound_cb)(
149 git_tree **out,
150 git_repository *repo,
151 git_tree *parent,
152 git_oid *note_oid,
153 const char *annotated_object_sha,
154 int fanout,
155 int current_error))
a02e7249 156{
56543a60 157 int error;
dca6b228 158 git_tree *subtree = NULL, *new = NULL;
a02e7249 159 char subtree_name[3];
bf477ed4 160
b93688d0
VM
161 error = find_subtree_in_current_level(
162 &subtree, repo, parent, annotated_object_sha, fanout);
bf477ed4 163
a02e7249 164 if (error == GIT_EEXISTS) {
b93688d0
VM
165 error = note_exists_cb(
166 out, repo, parent, note_oid, annotated_object_sha, fanout, error);
a02e7249 167 goto cleanup;
168 }
bf477ed4 169
a02e7249 170 if (error == GIT_ENOTFOUND) {
b93688d0
VM
171 error = note_notfound_cb(
172 out, repo, parent, note_oid, annotated_object_sha, fanout, error);
a02e7249 173 goto cleanup;
174 }
bf477ed4 175
4aa7de15 176 if (error < 0)
a02e7249 177 goto cleanup;
bf477ed4 178
a02e7249 179 /* An existing fanout has been found, let's dig deeper */
b93688d0 180 error = manipulate_note_in_tree_r(
dca6b228 181 &new, repo, subtree, note_oid, annotated_object_sha,
b93688d0 182 fanout + 2, note_exists_cb, note_notfound_cb);
bf477ed4 183
a02e7249 184 if (error < 0)
185 goto cleanup;
bf477ed4 186
a02e7249 187 strncpy(subtree_name, annotated_object_sha + fanout, 2);
188 subtree_name[2] = '\0';
bf477ed4 189
dca6b228 190 error = tree_write(out, repo, parent, git_tree_id(new),
a7dbac0b 191 subtree_name, GIT_FILEMODE_TREE);
dca6b228 192
4aa7de15 193
a02e7249 194cleanup:
dca6b228 195 git_tree_free(new);
a02e7249 196 git_tree_free(subtree);
197 return error;
198}
bf477ed4 199
b93688d0
VM
200static int remove_note_in_tree_eexists_cb(
201 git_tree **out,
202 git_repository *repo,
203 git_tree *parent,
204 git_oid *note_oid,
205 const char *annotated_object_sha,
206 int fanout,
207 int current_error)
208{
a02e7249 209 GIT_UNUSED(note_oid);
210 GIT_UNUSED(current_error);
bf477ed4 211
a02e7249 212 return tree_write(out, repo, parent, NULL, annotated_object_sha + fanout, 0);
213}
bf477ed4 214
b93688d0
VM
215static int remove_note_in_tree_enotfound_cb(
216 git_tree **out,
217 git_repository *repo,
218 git_tree *parent,
219 git_oid *note_oid,
220 const char *annotated_object_sha,
221 int fanout,
222 int current_error)
223{
a02e7249 224 GIT_UNUSED(out);
225 GIT_UNUSED(repo);
226 GIT_UNUSED(parent);
227 GIT_UNUSED(note_oid);
228 GIT_UNUSED(fanout);
bf477ed4 229
ac3d33df 230 git_error_set(GIT_ERROR_REPOSITORY, "object '%s' has no note", annotated_object_sha);
a02e7249 231 return current_error;
232}
bf477ed4 233
b93688d0
VM
234static int insert_note_in_tree_eexists_cb(git_tree **out,
235 git_repository *repo,
236 git_tree *parent,
237 git_oid *note_oid,
238 const char *annotated_object_sha,
239 int fanout,
240 int current_error)
241{
a02e7249 242 GIT_UNUSED(out);
243 GIT_UNUSED(repo);
244 GIT_UNUSED(parent);
245 GIT_UNUSED(note_oid);
246 GIT_UNUSED(fanout);
bf477ed4 247
ac3d33df 248 git_error_set(GIT_ERROR_REPOSITORY, "note for '%s' exists already", annotated_object_sha);
a02e7249 249 return current_error;
250}
bf477ed4 251
b93688d0
VM
252static int insert_note_in_tree_enotfound_cb(git_tree **out,
253 git_repository *repo,
254 git_tree *parent,
255 git_oid *note_oid,
256 const char *annotated_object_sha,
257 int fanout,
258 int current_error)
259{
a02e7249 260 GIT_UNUSED(current_error);
bf477ed4 261
a02e7249 262 /* No existing fanout at this level, insert in place */
a7dbac0b 263 return tree_write(
264 out,
265 repo,
266 parent,
267 note_oid,
268 annotated_object_sha + fanout,
269 GIT_FILEMODE_BLOB);
bf477ed4
MS
270}
271
eae0bfdc
PP
272static int note_write(
273 git_oid *notes_commit_out,
274 git_oid *notes_blob_out,
b93688d0 275 git_repository *repo,
de5596bf
BS
276 const git_signature *author,
277 const git_signature *committer,
b93688d0
VM
278 const char *notes_ref,
279 const char *note,
280 git_tree *commit_tree,
281 const char *target,
8716b499
NV
282 git_commit **parents,
283 int allow_note_overwrite)
bf477ed4 284{
a02e7249 285 int error;
bf477ed4 286 git_oid oid;
a02e7249 287 git_tree *tree = NULL;
4a44087a 288
ac3d33df 289 /* TODO: should we apply filters? */
a02e7249 290 /* create note object */
0c9c969a 291 if ((error = git_blob_create_from_buffer(&oid, repo, note, strlen(note))) < 0)
a02e7249 292 goto cleanup;
bf477ed4 293
b93688d0
VM
294 if ((error = manipulate_note_in_tree_r(
295 &tree, repo, commit_tree, &oid, target, 0,
8716b499
NV
296 allow_note_overwrite ? insert_note_in_tree_enotfound_cb : insert_note_in_tree_eexists_cb,
297 insert_note_in_tree_enotfound_cb)) < 0)
a02e7249 298 goto cleanup;
bf477ed4 299
eae0bfdc
PP
300 if (notes_blob_out)
301 git_oid_cpy(notes_blob_out, &oid);
302
4aa7de15 303
a02e7249 304 error = git_commit_create(&oid, repo, notes_ref, author, committer,
305 NULL, GIT_NOTES_DEFAULT_MSG_ADD,
306 tree, *parents == NULL ? 0 : 1, (const git_commit **) parents);
4aa7de15 307
eae0bfdc
PP
308 if (notes_commit_out)
309 git_oid_cpy(notes_commit_out, &oid);
310
a02e7249 311cleanup:
bf477ed4 312 git_tree_free(tree);
a02e7249 313 return error;
314}
bf477ed4 315
bad4937e
ET
316static int note_new(
317 git_note **out,
318 git_oid *note_oid,
319 git_commit *commit,
320 git_blob *blob)
a02e7249 321{
322 git_note *note = NULL;
0c9c969a 323 git_object_size_t blobsize;
bf477ed4 324
392702ee 325 note = git__malloc(sizeof(git_note));
ac3d33df 326 GIT_ERROR_CHECK_ALLOC(note);
bf477ed4 327
d0a3de72 328 git_oid_cpy(&note->id, note_oid);
bad4937e
ET
329
330 if (git_signature_dup(&note->author, git_commit_author(commit)) < 0 ||
331 git_signature_dup(&note->committer, git_commit_committer(commit)) < 0)
332 return -1;
333
ac3d33df
JK
334 blobsize = git_blob_rawsize(blob);
335 GIT_ERROR_CHECK_BLOBSIZE(blobsize);
336
337 note->message = git__strndup(git_blob_rawcontent(blob), (size_t)blobsize);
338 GIT_ERROR_CHECK_ALLOC(note->message);
bf477ed4
MS
339
340 *out = note;
a02e7249 341 return 0;
bf477ed4
MS
342}
343
734c6fc1 344static int note_lookup(
bad4937e
ET
345 git_note **out,
346 git_repository *repo,
347 git_commit *commit,
348 git_tree *tree,
349 const char *target)
bf477ed4
MS
350{
351 int error, fanout = 0;
352 git_oid oid;
a02e7249 353 git_blob *blob = NULL;
354 git_note *note = NULL;
355 git_tree *subtree = NULL;
bf477ed4 356
a02e7249 357 if ((error = find_subtree_r(&subtree, tree, repo, target, &fanout)) < 0)
358 goto cleanup;
bf477ed4 359
a02e7249 360 if ((error = find_blob(&oid, subtree, target + fanout)) < 0)
361 goto cleanup;
bf477ed4 362
a02e7249 363 if ((error = git_blob_lookup(&blob, repo, &oid)) < 0)
364 goto cleanup;
bf477ed4 365
bad4937e 366 if ((error = note_new(&note, &oid, commit, blob)) < 0)
a02e7249 367 goto cleanup;
bf477ed4 368
a02e7249 369 *out = note;
bf477ed4 370
a02e7249 371cleanup:
372 git_tree_free(subtree);
373 git_blob_free(blob);
374 return error;
375}
bf477ed4 376
eae0bfdc
PP
377static int note_remove(
378 git_oid *notes_commit_out,
379 git_repository *repo,
de5596bf
BS
380 const git_signature *author, const git_signature *committer,
381 const char *notes_ref, git_tree *tree,
382 const char *target, git_commit **parents)
a02e7249 383{
384 int error;
385 git_tree *tree_after_removal = NULL;
386 git_oid oid;
4a44087a 387
b93688d0
VM
388 if ((error = manipulate_note_in_tree_r(
389 &tree_after_removal, repo, tree, NULL, target, 0,
390 remove_note_in_tree_eexists_cb, remove_note_in_tree_enotfound_cb)) < 0)
a02e7249 391 goto cleanup;
bf477ed4
MS
392
393 error = git_commit_create(&oid, repo, notes_ref, author, committer,
b93688d0
VM
394 NULL, GIT_NOTES_DEFAULT_MSG_RM,
395 tree_after_removal,
396 *parents == NULL ? 0 : 1,
397 (const git_commit **) parents);
bf477ed4 398
eae0bfdc
PP
399 if (error < 0)
400 goto cleanup;
401
402 if (notes_commit_out)
403 git_oid_cpy(notes_commit_out, &oid);
404
a02e7249 405cleanup:
406 git_tree_free(tree_after_removal);
bf477ed4
MS
407 return error;
408}
409
385449b1 410static int note_get_default_ref(char **out, git_repository *repo)
caea5e54 411{
caea5e54 412 git_config *cfg;
9f77b3f6 413 int ret = git_repository_config__weakptr(&cfg, repo);
caea5e54 414
9f77b3f6
RB
415 *out = (ret != 0) ? NULL : git_config__get_string_force(
416 cfg, "core.notesref", GIT_NOTES_DEFAULT_REF);
caea5e54 417
f95e8cc0 418 return ret;
caea5e54
MS
419}
420
385449b1 421static int normalize_namespace(char **out, git_repository *repo, const char *notes_ref)
86ecd844 422{
385449b1
CMN
423 if (notes_ref) {
424 *out = git__strdup(notes_ref);
ac3d33df 425 GIT_ERROR_CHECK_ALLOC(*out);
86ecd844 426 return 0;
385449b1 427 }
86ecd844 428
385449b1 429 return note_get_default_ref(out, repo);
86ecd844 430}
431
eae0bfdc 432static int retrieve_note_commit(
b93688d0 433 git_commit **commit_out,
385449b1 434 char **notes_ref_out,
b93688d0 435 git_repository *repo,
385449b1 436 const char *notes_ref)
86ecd844 437{
a02e7249 438 int error;
86ecd844 439 git_oid oid;
440
385449b1 441 if ((error = normalize_namespace(notes_ref_out, repo, notes_ref)) < 0)
a02e7249 442 return error;
86ecd844 443
385449b1 444 if ((error = git_reference_name_to_id(&oid, repo, *notes_ref_out)) < 0)
a02e7249 445 return error;
86ecd844 446
a02e7249 447 if (git_commit_lookup(commit_out, repo, &oid) < 0)
448 return error;
86ecd844 449
a02e7249 450 return 0;
86ecd844 451}
452
eae0bfdc
PP
453int git_note_commit_read(
454 git_note **out,
455 git_repository *repo,
456 git_commit *notes_commit,
457 const git_oid *oid)
458{
459 int error;
460 git_tree *tree = NULL;
461 char target[GIT_OID_HEXSZ + 1];
462
463 git_oid_tostr(target, sizeof(target), oid);
464
465 if ((error = git_commit_tree(&tree, notes_commit)) < 0)
466 goto cleanup;
467
468 error = note_lookup(out, repo, notes_commit, tree, target);
469
470cleanup:
471 git_tree_free(tree);
472 return error;
473}
474
bf477ed4 475int git_note_read(git_note **out, git_repository *repo,
385449b1 476 const char *notes_ref_in, const git_oid *oid)
bf477ed4
MS
477{
478 int error;
eae0bfdc 479 char *notes_ref = NULL;
a02e7249 480 git_commit *commit = NULL;
bf477ed4 481
eae0bfdc 482 error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
bf477ed4 483
eae0bfdc
PP
484 if (error < 0)
485 goto cleanup;
bf477ed4 486
eae0bfdc
PP
487 error = git_note_commit_read(out, repo, commit, oid);
488
489cleanup:
385449b1 490 git__free(notes_ref);
a02e7249 491 git_commit_free(commit);
4aa7de15 492 return error;
bf477ed4
MS
493}
494
eae0bfdc
PP
495int git_note_commit_create(
496 git_oid *notes_commit_out,
497 git_oid *notes_blob_out,
498 git_repository *repo,
499 git_commit *parent,
500 const git_signature *author,
501 const git_signature *committer,
502 const git_oid *oid,
503 const char *note,
504 int allow_note_overwrite)
505{
506 int error;
507 git_tree *tree = NULL;
508 char target[GIT_OID_HEXSZ + 1];
509
510 git_oid_tostr(target, sizeof(target), oid);
511
512 if (parent != NULL && (error = git_commit_tree(&tree, parent)) < 0)
513 goto cleanup;
514
515 error = note_write(notes_commit_out, notes_blob_out, repo, author,
516 committer, NULL, note, tree, target, &parent, allow_note_overwrite);
517
518 if (error < 0)
519 goto cleanup;
520
521cleanup:
522 git_tree_free(tree);
523 return error;
524}
525
4aa7de15 526int git_note_create(
de5596bf
BS
527 git_oid *out,
528 git_repository *repo,
385449b1 529 const char *notes_ref_in,
de5596bf
BS
530 const git_signature *author,
531 const git_signature *committer,
de5596bf 532 const git_oid *oid,
8716b499
NV
533 const char *note,
534 int allow_note_overwrite)
bf477ed4 535{
a02e7249 536 int error;
eae0bfdc
PP
537 char *notes_ref = NULL;
538 git_commit *existing_notes_commit = NULL;
539 git_reference *ref = NULL;
540 git_oid notes_blob_oid, notes_commit_oid;
bf477ed4 541
eae0bfdc
PP
542 error = retrieve_note_commit(&existing_notes_commit, &notes_ref,
543 repo, notes_ref_in);
a02e7249 544
545 if (error < 0 && error != GIT_ENOTFOUND)
546 goto cleanup;
547
eae0bfdc
PP
548 error = git_note_commit_create(&notes_commit_oid,
549 &notes_blob_oid,
550 repo, existing_notes_commit, author,
551 committer, oid, note,
552 allow_note_overwrite);
553 if (error < 0)
554 goto cleanup;
555
556 error = git_reference_create(&ref, repo, notes_ref,
557 &notes_commit_oid, 1, NULL);
558
559 if (out != NULL)
560 git_oid_cpy(out, &notes_blob_oid);
bf477ed4 561
a02e7249 562cleanup:
385449b1 563 git__free(notes_ref);
eae0bfdc
PP
564 git_commit_free(existing_notes_commit);
565 git_reference_free(ref);
566 return error;
567}
568
569int git_note_commit_remove(
570 git_oid *notes_commit_out,
571 git_repository *repo,
572 git_commit *notes_commit,
573 const git_signature *author,
574 const git_signature *committer,
575 const git_oid *oid)
576{
577 int error;
578 git_tree *tree = NULL;
579 char target[GIT_OID_HEXSZ + 1];
580
581 git_oid_tostr(target, sizeof(target), oid);
582
583 if ((error = git_commit_tree(&tree, notes_commit)) < 0)
584 goto cleanup;
585
586 error = note_remove(notes_commit_out,
587 repo, author, committer, NULL, tree, target, &notes_commit);
588
589cleanup:
a02e7249 590 git_tree_free(tree);
4aa7de15 591 return error;
bf477ed4
MS
592}
593
385449b1 594int git_note_remove(git_repository *repo, const char *notes_ref_in,
de5596bf
BS
595 const git_signature *author, const git_signature *committer,
596 const git_oid *oid)
bf477ed4
MS
597{
598 int error;
eae0bfdc
PP
599 char *notes_ref_target = NULL;
600 git_commit *existing_notes_commit = NULL;
601 git_oid new_notes_commit;
602 git_reference *notes_ref = NULL;
bf477ed4 603
eae0bfdc
PP
604 error = retrieve_note_commit(&existing_notes_commit, &notes_ref_target,
605 repo, notes_ref_in);
bf477ed4 606
eae0bfdc
PP
607 if (error < 0)
608 goto cleanup;
bf477ed4 609
eae0bfdc
PP
610 error = git_note_commit_remove(&new_notes_commit, repo,
611 existing_notes_commit, author, committer, oid);
612 if (error < 0)
613 goto cleanup;
614
615 error = git_reference_create(&notes_ref, repo, notes_ref_target,
616 &new_notes_commit, 1, NULL);
617
618cleanup:
619 git__free(notes_ref_target);
620 git_reference_free(notes_ref);
621 git_commit_free(existing_notes_commit);
4aa7de15 622 return error;
bf477ed4
MS
623}
624
385449b1 625int git_note_default_ref(git_buf *out, git_repository *repo)
630c5a4a 626{
385449b1
CMN
627 char *default_ref;
628 int error;
629
630 assert(out && repo);
631
632 git_buf_sanitize(out);
633
634 if ((error = note_get_default_ref(&default_ref, repo)) < 0)
635 return error;
636
637 git_buf_attach(out, default_ref, strlen(default_ref));
638 return 0;
630c5a4a
MS
639}
640
bad4937e
ET
641const git_signature *git_note_committer(const git_note *note)
642{
643 assert(note);
644 return note->committer;
645}
646
647const git_signature *git_note_author(const git_note *note)
648{
649 assert(note);
650 return note->author;
651}
652
de5596bf 653const char * git_note_message(const git_note *note)
bf477ed4
MS
654{
655 assert(note);
656 return note->message;
657}
658
d0a3de72 659const git_oid * git_note_id(const git_note *note)
bf477ed4
MS
660{
661 assert(note);
d0a3de72 662 return &note->id;
bf477ed4
MS
663}
664
665void git_note_free(git_note *note)
666{
667 if (note == NULL)
668 return;
669
bad4937e
ET
670 git_signature_free(note->committer);
671 git_signature_free(note->author);
bf477ed4
MS
672 git__free(note->message);
673 git__free(note);
674}
86ecd844 675
676static int process_entry_path(
677 const char* entry_path,
f7b18502 678 git_oid *annotated_object_id)
86ecd844 679{
734c6fc1 680 int error = 0;
b8457baa 681 size_t i = 0, j = 0, len;
86ecd844 682 git_buf buf = GIT_BUF_INIT;
683
5dca2010 684 if ((error = git_buf_puts(&buf, entry_path)) < 0)
86ecd844 685 goto cleanup;
5dca2010 686
86ecd844 687 len = git_buf_len(&buf);
688
689 while (i < len) {
690 if (buf.ptr[i] == '/') {
691 i++;
692 continue;
693 }
5dca2010 694
86ecd844 695 if (git__fromhex(buf.ptr[i]) < 0) {
696 /* This is not a note entry */
86ecd844 697 goto cleanup;
698 }
699
700 if (i != j)
701 buf.ptr[j] = buf.ptr[i];
702
703 i++;
704 j++;
705 }
706
707 buf.ptr[j] = '\0';
708 buf.size = j;
709
710 if (j != GIT_OID_HEXSZ) {
711 /* This is not a note entry */
86ecd844 712 goto cleanup;
713 }
714
f7b18502 715 error = git_oid_fromstr(annotated_object_id, buf.ptr);
86ecd844 716
86ecd844 717cleanup:
ac3d33df 718 git_buf_dispose(&buf);
86ecd844 719 return error;
720}
721
722int git_note_foreach(
0cb16fe9
L
723 git_repository *repo,
724 const char *notes_ref,
725 git_note_foreach_cb note_cb,
726 void *payload)
86ecd844 727{
0cb16fe9
L
728 int error;
729 git_note_iterator *iter = NULL;
730 git_oid note_id, annotated_id;
6edb427b 731
0cb16fe9
L
732 if ((error = git_note_iterator_new(&iter, repo, notes_ref)) < 0)
733 return error;
86ecd844 734
f10d7a36
RB
735 while (!(error = git_note_next(&note_id, &annotated_id, iter))) {
736 if ((error = note_cb(&note_id, &annotated_id, payload)) != 0) {
ac3d33df 737 git_error_set_after_callback(error);
f10d7a36
RB
738 break;
739 }
740 }
86ecd844 741
0cb16fe9
L
742 if (error == GIT_ITEROVER)
743 error = 0;
5dca2010 744
0cb16fe9
L
745 git_note_iterator_free(iter);
746 return error;
86ecd844 747}
6edb427b 748
1a90dcf6
NG
749void git_note_iterator_free(git_note_iterator *it)
750{
751 if (it == NULL)
752 return;
753
754 git_iterator_free(it);
755}
756
eae0bfdc
PP
757int git_note_commit_iterator_new(
758 git_note_iterator **it,
759 git_commit *notes_commit)
760{
761 int error;
762 git_tree *tree;
763
764 if ((error = git_commit_tree(&tree, notes_commit)) < 0)
765 goto cleanup;
766
767 if ((error = git_iterator_for_tree(it, tree, NULL)) < 0)
768 git_iterator_free(*it);
769
770cleanup:
771 git_tree_free(tree);
772
773 return error;
774}
1a90dcf6 775
6edb427b 776int git_note_iterator_new(
1a90dcf6 777 git_note_iterator **it,
6edb427b 778 git_repository *repo,
385449b1 779 const char *notes_ref_in)
6edb427b
NG
780{
781 int error;
782 git_commit *commit = NULL;
385449b1 783 char *notes_ref;
6edb427b 784
eae0bfdc 785 error = retrieve_note_commit(&commit, &notes_ref, repo, notes_ref_in);
f7b18502
NG
786 if (error < 0)
787 goto cleanup;
6edb427b 788
eae0bfdc 789 error = git_note_commit_iterator_new(it, commit);
6edb427b 790
f7b18502 791cleanup:
385449b1 792 git__free(notes_ref);
6edb427b
NG
793 git_commit_free(commit);
794
795 return error;
796}
797
798int git_note_next(
799 git_oid* note_id,
800 git_oid* annotated_id,
f7b18502 801 git_note_iterator *it)
6edb427b
NG
802{
803 int error;
804 const git_index_entry *item;
805
169dc616 806 if ((error = git_iterator_current(&item, it)) < 0)
cee695ae 807 return error;
6edb427b 808
d541170c 809 git_oid_cpy(note_id, &item->id);
6edb427b 810
66a70851
UG
811 if ((error = process_entry_path(item->path, annotated_id)) < 0)
812 return error;
6edb427b 813
66a70851
UG
814 if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER)
815 return error;
816
817 return 0;
6edb427b 818}