object: introduce a raw content validation function Users may want to validate raw object content; provide them a function to do so.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
diff --git a/include/git2/object.h b/include/git2/object.h
index 984dbb7..dbf480e 100644
--- a/include/git2/object.h
+++ b/include/git2/object.h
@@ -224,6 +224,28 @@ GIT_EXTERN(int) git_object_peel(
*/
GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source);
+/**
+ * Analyzes a buffer of raw object content and determines its validity.
+ * Tree, commit, and tag objects will be parsed and ensured that they
+ * are valid, parseable content. (Blobs are always valid by definition.)
+ * An error message will be set with an informative message if the object
+ * is not valid.
+ *
+ * @warning This function is experimental and its signature may change in
+ * the future.
+ *
+ * @param valid Output pointer to set with validity of the object content
+ * @param buf The contents to validate
+ * @param len The length of the buffer
+ * @param type The type of the object in the buffer
+ * @return 0 on success or an error code
+ */
+GIT_EXTERN(int) git_object_rawcontent_is_valid(
+ int *valid,
+ const char *buf,
+ size_t len,
+ git_object_t type);
+
/** @} */
GIT_END_DECL
diff --git a/src/object.c b/src/object.c
index 7e6ad3a..7bc256f 100644
--- a/src/object.c
+++ b/src/object.c
@@ -567,3 +567,35 @@ bool git_object__is_valid(
return true;
}
+
+int git_object_rawcontent_is_valid(
+ int *valid,
+ const char *buf,
+ size_t len,
+ git_object_t type)
+{
+ git_object *obj = NULL;
+ int error;
+
+ GIT_ASSERT_ARG(valid);
+ GIT_ASSERT_ARG(buf);
+
+ /* Blobs are always valid; don't bother parsing. */
+ if (type == GIT_OBJECT_BLOB) {
+ *valid = 1;
+ return 0;
+ }
+
+ error = git_object__from_raw(&obj, buf, len, type);
+ git_object_free(obj);
+
+ if (error == 0) {
+ *valid = 1;
+ return 0;
+ } else if (error == GIT_EINVALID) {
+ *valid = 0;
+ return 0;
+ }
+
+ return error;
+}
diff --git a/tests/object/validate.c b/tests/object/validate.c
new file mode 100644
index 0000000..87193de
--- /dev/null
+++ b/tests/object/validate.c
@@ -0,0 +1,50 @@
+#include "clar_libgit2.h"
+
+#define VALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
+ "parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
+ "author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
+ "committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
+ "\n" \
+ "commit go here.\n"
+#define VALID_TREE "100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
+
+#define INVALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
+ "parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
+ "committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
+ "\n" \
+ "commit go here.\n"
+#define INVALID_TREE "100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
+
+void test_object_validate__valid(void)
+{
+ int valid;
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB));
+ cl_assert_equal_i(1, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB));
+ cl_assert_equal_i(1, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT, CONST_STRLEN(VALID_COMMIT), GIT_OBJECT_COMMIT));
+ cl_assert_equal_i(1, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_TREE, CONST_STRLEN(VALID_TREE), GIT_OBJECT_TREE));
+ cl_assert_equal_i(1, valid);
+}
+
+void test_object_validate__invalid(void)
+{
+ int valid;
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT));
+ cl_assert_equal_i(0, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT));
+ cl_assert_equal_i(0, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_COMMIT, CONST_STRLEN(INVALID_COMMIT), GIT_OBJECT_COMMIT));
+ cl_assert_equal_i(0, valid);
+
+ cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE, CONST_STRLEN(INVALID_TREE), GIT_OBJECT_TREE));
+ cl_assert_equal_i(0, valid);
+}