Skip to content

Commit 30675f7

Browse files
committed
Merge branch 'mh/notes-cleanup'
Code clean-up. * mh/notes-cleanup: load_subtree(): check that `prefix_len` is in the expected range load_subtree(): declare some variables to be `size_t` hex_to_bytes(): simpler replacement for `get_oid_hex_segment()` get_oid_hex_segment(): don't pad the rest of `oid` load_subtree(): combine some common code get_oid_hex_segment(): return 0 on success load_subtree(): only consider blobs to be potential notes load_subtree(): check earlier whether an internal node is a tree entry load_subtree(): separate logic for internal vs. terminal entries load_subtree(): fix incorrect comment load_subtree(): reduce the scope of some local variables load_subtree(): remove unnecessary conditional notes: make GET_NIBBLE macro more robust
2 parents eb06642 + 3964281 commit 30675f7

1 file changed

Lines changed: 70 additions & 71 deletions

File tree

notes.c

Lines changed: 70 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ struct non_note {
6464
#define CLR_PTR_TYPE(ptr) ((void *) ((uintptr_t) (ptr) & ~3))
6565
#define SET_PTR_TYPE(ptr, type) ((void *) ((uintptr_t) (ptr) | (type)))
6666

67-
#define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)
67+
#define GET_NIBBLE(n, sha1) ((((sha1)[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)
6868

6969
#define KEY_INDEX (GIT_SHA1_RAWSZ - 1)
7070
#define FANOUT_PATH_SEPARATORS ((GIT_SHA1_HEXSZ / 2) - 1)
@@ -335,31 +335,20 @@ static void note_tree_free(struct int_node *tree)
335335
}
336336

337337
/*
338-
* Convert a partial SHA1 hex string to the corresponding partial SHA1 value.
339-
* - hex - Partial SHA1 segment in ASCII hex format
340-
* - hex_len - Length of above segment. Must be multiple of 2 between 0 and 40
341-
* - sha1 - Partial SHA1 value is written here
342-
* - sha1_len - Max #bytes to store in sha1, Must be >= hex_len / 2, and < 20
343-
* Returns -1 on error (invalid arguments or invalid SHA1 (not in hex format)).
344-
* Otherwise, returns number of bytes written to sha1 (i.e. hex_len / 2).
345-
* Pads sha1 with NULs up to sha1_len (not included in returned length).
338+
* Read `len` pairs of hexadecimal digits from `hex` and write the
339+
* values to `binary` as `len` bytes. Return 0 on success, or -1 if
340+
* the input does not consist of hex digits).
346341
*/
347-
static int get_oid_hex_segment(const char *hex, unsigned int hex_len,
348-
unsigned char *oid, unsigned int oid_len)
342+
static int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
349343
{
350-
unsigned int i, len = hex_len >> 1;
351-
if (hex_len % 2 != 0 || len > oid_len)
352-
return -1;
353-
for (i = 0; i < len; i++) {
344+
for (; len; len--, hex += 2) {
354345
unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
346+
355347
if (val & ~0xff)
356348
return -1;
357-
*oid++ = val;
358-
hex += 2;
349+
*binary++ = val;
359350
}
360-
for (; i < oid_len; i++)
361-
*oid++ = 0;
362-
return len;
351+
return 0;
363352
}
364353

365354
static int non_note_cmp(const struct non_note *a, const struct non_note *b)
@@ -417,80 +406,90 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
417406
struct int_node *node, unsigned int n)
418407
{
419408
struct object_id object_oid;
420-
unsigned int prefix_len;
409+
size_t prefix_len;
421410
void *buf;
422411
struct tree_desc desc;
423412
struct name_entry entry;
424-
int len, path_len;
425-
unsigned char type;
426-
struct leaf_node *l;
427413

428414
buf = fill_tree_descriptor(&desc, &subtree->val_oid);
429415
if (!buf)
430416
die("Could not read %s for notes-index",
431417
oid_to_hex(&subtree->val_oid));
432418

433419
prefix_len = subtree->key_oid.hash[KEY_INDEX];
434-
assert(prefix_len * 2 >= n);
420+
if (prefix_len >= GIT_SHA1_RAWSZ)
421+
BUG("prefix_len (%"PRIuMAX") is out of range", (uintmax_t)prefix_len);
422+
if (prefix_len * 2 < n)
423+
BUG("prefix_len (%"PRIuMAX") is too small", (uintmax_t)prefix_len);
435424
memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len);
436425
while (tree_entry(&desc, &entry)) {
437-
path_len = strlen(entry.path);
438-
len = get_oid_hex_segment(entry.path, path_len,
439-
object_oid.hash + prefix_len, GIT_SHA1_RAWSZ - prefix_len);
440-
if (len < 0)
441-
goto handle_non_note; /* entry.path is not a SHA1 */
442-
len += prefix_len;
426+
unsigned char type;
427+
struct leaf_node *l;
428+
size_t path_len = strlen(entry.path);
429+
430+
if (path_len == 2 * (GIT_SHA1_RAWSZ - prefix_len)) {
431+
/* This is potentially the remainder of the SHA-1 */
432+
433+
if (!S_ISREG(entry.mode))
434+
/* notes must be blobs */
435+
goto handle_non_note;
436+
437+
if (hex_to_bytes(object_oid.hash + prefix_len, entry.path,
438+
GIT_SHA1_RAWSZ - prefix_len))
439+
goto handle_non_note; /* entry.path is not a SHA1 */
443440

444-
/*
445-
* If object SHA1 is complete (len == 20), assume note object
446-
* If object SHA1 is incomplete (len < 20), and current
447-
* component consists of 2 hex chars, assume note subtree
448-
*/
449-
if (len <= GIT_SHA1_RAWSZ) {
450441
type = PTR_TYPE_NOTE;
451-
l = (struct leaf_node *)
452-
xcalloc(1, sizeof(struct leaf_node));
453-
oidcpy(&l->key_oid, &object_oid);
454-
oidcpy(&l->val_oid, entry.oid);
455-
if (len < GIT_SHA1_RAWSZ) {
456-
if (!S_ISDIR(entry.mode) || path_len != 2)
457-
goto handle_non_note; /* not subtree */
458-
l->key_oid.hash[KEY_INDEX] = (unsigned char) len;
459-
type = PTR_TYPE_SUBTREE;
460-
}
461-
if (note_tree_insert(t, node, n, l, type,
462-
combine_notes_concatenate))
463-
die("Failed to load %s %s into notes tree "
464-
"from %s",
465-
type == PTR_TYPE_NOTE ? "note" : "subtree",
466-
oid_to_hex(&l->key_oid), t->ref);
442+
} else if (path_len == 2) {
443+
/* This is potentially an internal node */
444+
size_t len = prefix_len;
445+
446+
if (!S_ISDIR(entry.mode))
447+
/* internal nodes must be trees */
448+
goto handle_non_note;
449+
450+
if (hex_to_bytes(object_oid.hash + len++, entry.path, 1))
451+
goto handle_non_note; /* entry.path is not a SHA1 */
452+
453+
/*
454+
* Pad the rest of the SHA-1 with zeros,
455+
* except for the last byte, where we write
456+
* the length:
457+
*/
458+
memset(object_oid.hash + len, 0, GIT_SHA1_RAWSZ - len - 1);
459+
object_oid.hash[KEY_INDEX] = (unsigned char)len;
460+
461+
type = PTR_TYPE_SUBTREE;
462+
} else {
463+
/* This can't be part of a note */
464+
goto handle_non_note;
467465
}
466+
467+
l = xcalloc(1, sizeof(*l));
468+
oidcpy(&l->key_oid, &object_oid);
469+
oidcpy(&l->val_oid, entry.oid);
470+
if (note_tree_insert(t, node, n, l, type,
471+
combine_notes_concatenate))
472+
die("Failed to load %s %s into notes tree "
473+
"from %s",
474+
type == PTR_TYPE_NOTE ? "note" : "subtree",
475+
oid_to_hex(&l->key_oid), t->ref);
476+
468477
continue;
469478

470479
handle_non_note:
471480
/*
472-
* Determine full path for this non-note entry:
473-
* The filename is already found in entry.path, but the
474-
* directory part of the path must be deduced from the subtree
475-
* containing this entry. We assume here that the overall notes
476-
* tree follows a strict byte-based progressive fanout
477-
* structure (i.e. using 2/38, 2/2/36, etc. fanouts, and not
478-
* e.g. 4/36 fanout). This means that if a non-note is found at
479-
* path "dead/beef", the following code will register it as
480-
* being found on "de/ad/beef".
481-
* On the other hand, if you use such non-obvious non-note
482-
* paths in the middle of a notes tree, you deserve what's
483-
* coming to you ;). Note that for non-notes that are not
484-
* SHA1-like at the top level, there will be no problems.
485-
*
486-
* To conclude, it is strongly advised to make sure non-notes
487-
* have at least one non-hex character in the top-level path
488-
* component.
481+
* Determine full path for this non-note entry. The
482+
* filename is already found in entry.path, but the
483+
* directory part of the path must be deduced from the
484+
* subtree containing this entry based on our
485+
* knowledge that the overall notes tree follows a
486+
* strict byte-based progressive fanout structure
487+
* (i.e. using 2/38, 2/2/36, etc. fanouts).
489488
*/
490489
{
491490
struct strbuf non_note_path = STRBUF_INIT;
492491
const char *q = oid_to_hex(&subtree->key_oid);
493-
int i;
492+
size_t i;
494493
for (i = 0; i < prefix_len; i++) {
495494
strbuf_addch(&non_note_path, *q++);
496495
strbuf_addch(&non_note_path, *q++);

0 commit comments

Comments
 (0)