@@ -49,8 +49,37 @@ static git_cache *odb_cache(git_odb *odb)
49
49
return & odb -> own_cache ;
50
50
}
51
51
52
+ static int odb_otype_fast (git_otype * type_p , git_odb * db , const git_oid * id );
52
53
static int load_alternates (git_odb * odb , const char * objects_dir , int alternate_depth );
53
54
55
+ static git_otype odb_hardcoded_type (const git_oid * id )
56
+ {
57
+ static git_oid empty_blob = {{ 0xe6 , 0x9d , 0xe2 , 0x9b , 0xb2 , 0xd1 , 0xd6 , 0x43 , 0x4b , 0x8b ,
58
+ 0x29 , 0xae , 0x77 , 0x5a , 0xd8 , 0xc2 , 0xe4 , 0x8c , 0x53 , 0x91 }};
59
+ static git_oid empty_tree = {{ 0x4b , 0x82 , 0x5d , 0xc6 , 0x42 , 0xcb , 0x6e , 0xb9 , 0xa0 , 0x60 ,
60
+ 0xe5 , 0x4b , 0xf8 , 0xd6 , 0x92 , 0x88 , 0xfb , 0xee , 0x49 , 0x04 }};
61
+
62
+ if (!git_oid_cmp (id , & empty_blob ))
63
+ return GIT_OBJ_BLOB ;
64
+
65
+ if (!git_oid_cmp (id , & empty_tree ))
66
+ return GIT_OBJ_TREE ;
67
+
68
+ return GIT_OBJ_BAD ;
69
+ }
70
+
71
+ static int odb_read_hardcoded (git_rawobj * raw , const git_oid * id )
72
+ {
73
+ git_otype type = odb_hardcoded_type (id );
74
+ if (type == GIT_OBJ_BAD )
75
+ return -1 ;
76
+
77
+ raw -> type = type ;
78
+ raw -> len = 0 ;
79
+ raw -> data = git__calloc (1 , sizeof (uint8_t ));
80
+ return 0 ;
81
+ }
82
+
54
83
int git_odb__format_object_header (char * hdr , size_t n , git_off_t obj_len , git_otype obj_type )
55
84
{
56
85
const char * type_str = git_object_type2string (obj_type );
@@ -747,55 +776,65 @@ int git_odb_expand_ids(
747
776
git_odb_expand_id * ids ,
748
777
size_t count )
749
778
{
750
- size_t len , i ;
751
- int error ;
779
+ size_t i ;
752
780
753
781
assert (db && ids );
754
782
755
783
for (i = 0 ; i < count ; i ++ ) {
756
784
git_odb_expand_id * query = & ids [i ];
757
- git_oid * actual_id = NULL , tmp ;
758
- git_otype query_type = (query -> type == GIT_OBJ_ANY ) ? 0 : query -> type ;
759
- git_otype actual_type = 0 ;
785
+ int error = GIT_EAMBIGUOUS ;
760
786
761
- /* if we were given a full object ID, simply look it up */
762
- if (query -> length >= GIT_OID_HEXSZ ) {
763
- error = git_odb_read_header (& len , & actual_type , db , & query -> id );
787
+ if (!query -> type )
788
+ query -> type = GIT_OBJ_ANY ;
789
+
790
+ /* if we have a short OID, expand it first */
791
+ if (query -> length >= GIT_OID_MINPREFIXLEN && query -> length < GIT_OID_HEXSZ ) {
792
+ git_oid actual_id ;
793
+
794
+ error = odb_exists_prefix_1 (& actual_id , db , & query -> id , query -> length , false);
795
+ if (!error ) {
796
+ git_oid_cpy (& query -> id , & actual_id );
797
+ query -> length = GIT_OID_HEXSZ ;
798
+ }
764
799
}
765
800
766
- /* otherwise, resolve the short id to full, then (optionally)
767
- * read the header.
801
+ /*
802
+ * now we ought to have a 40-char OID, either because we've expanded it
803
+ * or because the user passed a full OID. Ensure its type is right.
768
804
*/
769
- else if (query -> length >= GIT_OID_MINPREFIXLEN ) {
770
- error = odb_exists_prefix_1 (& tmp ,
771
- db , & query -> id , query -> length , false);
805
+ if (query -> length >= GIT_OID_HEXSZ ) {
806
+ git_otype actual_type ;
772
807
808
+ error = odb_otype_fast (& actual_type , db , & query -> id );
773
809
if (!error ) {
774
- actual_id = & tmp ;
775
- error = git_odb_read_header (& len , & actual_type , db , & tmp );
810
+ if (query -> type != GIT_OBJ_ANY && query -> type != actual_type )
811
+ error = GIT_ENOTFOUND ;
812
+ else
813
+ query -> type = actual_type ;
776
814
}
777
815
}
778
816
779
- if (error < 0 && error != GIT_ENOTFOUND && error != GIT_EAMBIGUOUS )
780
- break ;
781
-
782
- if (error == 0 && (query_type == actual_type || !query_type )) {
783
- if (actual_id )
784
- git_oid_cpy (& query -> id , actual_id );
817
+ switch (error ) {
818
+ /* no errors, so we've successfully expanded the OID */
819
+ case 0 :
820
+ continue ;
785
821
786
- query -> length = GIT_OID_HEXSZ ;
787
- query -> type = actual_type ;
788
- } else {
822
+ /* the object is missing or ambiguous */
823
+ case GIT_ENOTFOUND :
824
+ case GIT_EAMBIGUOUS :
789
825
memset (& query -> id , 0 , sizeof (git_oid ));
790
826
query -> length = 0 ;
791
827
query -> type = 0 ;
828
+ break ;
829
+
830
+ /* something went very wrong with the ODB; bail hard */
831
+ default :
832
+ return error ;
792
833
}
793
834
}
794
835
795
- if (!error )
796
- giterr_clear ();
797
-
798
- return error ;
836
+ giterr_clear ();
837
+ return 0 ;
799
838
}
800
839
801
840
int git_odb_read_header (size_t * len_p , git_otype * type_p , git_odb * db , const git_oid * id )
@@ -811,11 +850,53 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
811
850
return error ;
812
851
}
813
852
853
+ static int odb_read_header_1 (
854
+ size_t * len_p , git_otype * type_p , git_odb * db ,
855
+ const git_oid * id , bool only_refreshed )
856
+ {
857
+ size_t i ;
858
+ git_otype ht ;
859
+ bool passthrough = false;
860
+ int error ;
861
+
862
+ if (!only_refreshed && (ht = odb_hardcoded_type (id )) != GIT_OBJ_BAD ) {
863
+ * type_p = ht ;
864
+ * len_p = 0 ;
865
+ return 0 ;
866
+ }
867
+
868
+ for (i = 0 ; i < db -> backends .length ; ++ i ) {
869
+ backend_internal * internal = git_vector_get (& db -> backends , i );
870
+ git_odb_backend * b = internal -> backend ;
871
+
872
+ if (only_refreshed && !b -> refresh )
873
+ continue ;
874
+
875
+ if (!b -> read_header ) {
876
+ passthrough = true;
877
+ continue ;
878
+ }
879
+
880
+ error = b -> read_header (len_p , type_p , b , id );
881
+
882
+ switch (error ) {
883
+ case GIT_PASSTHROUGH :
884
+ passthrough = true;
885
+ break ;
886
+ case GIT_ENOTFOUND :
887
+ break ;
888
+ default :
889
+ return error ;
890
+ }
891
+ }
892
+
893
+ return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND ;
894
+ }
895
+
814
896
int git_odb__read_header_or_object (
815
897
git_odb_object * * out , size_t * len_p , git_otype * type_p ,
816
898
git_odb * db , const git_oid * id )
817
899
{
818
- size_t i ;
819
900
int error = GIT_ENOTFOUND ;
820
901
git_odb_object * object ;
821
902
@@ -829,52 +910,32 @@ int git_odb__read_header_or_object(
829
910
}
830
911
831
912
* out = NULL ;
913
+ error = odb_read_header_1 (len_p , type_p , db , id , false);
832
914
833
- for (i = 0 ; i < db -> backends .length && error < 0 ; ++ i ) {
834
- backend_internal * internal = git_vector_get (& db -> backends , i );
835
- git_odb_backend * b = internal -> backend ;
915
+ if (error == GIT_ENOTFOUND && !git_odb_refresh (db ))
916
+ error = odb_read_header_1 (len_p , type_p , db , id , true);
836
917
837
- if (b -> read_header != NULL )
838
- error = b -> read_header (len_p , type_p , b , id );
839
- }
918
+ if (error == GIT_ENOTFOUND )
919
+ return git_odb__error_notfound ("cannot read header for" , id , GIT_OID_HEXSZ );
840
920
841
- if (!error || error == GIT_PASSTHROUGH )
921
+ /* we found the header; return early */
922
+ if (!error )
842
923
return 0 ;
843
924
844
- /*
845
- * no backend could read only the header.
846
- * try reading the whole object and freeing the contents
847
- */
848
- if ((error = git_odb_read (& object , db , id )) < 0 )
849
- return error ; /* error already set - pass along */
850
-
851
- * len_p = object -> cached .size ;
852
- * type_p = object -> cached .type ;
853
- * out = object ;
854
-
855
- return 0 ;
856
- }
857
-
858
- static git_oid empty_blob = {{ 0xe6 , 0x9d , 0xe2 , 0x9b , 0xb2 , 0xd1 , 0xd6 , 0x43 , 0x4b , 0x8b ,
859
- 0x29 , 0xae , 0x77 , 0x5a , 0xd8 , 0xc2 , 0xe4 , 0x8c , 0x53 , 0x91 }};
860
- static git_oid empty_tree = {{ 0x4b , 0x82 , 0x5d , 0xc6 , 0x42 , 0xcb , 0x6e , 0xb9 , 0xa0 , 0x60 ,
861
- 0xe5 , 0x4b , 0xf8 , 0xd6 , 0x92 , 0x88 , 0xfb , 0xee , 0x49 , 0x04 }};
862
-
863
- static int hardcoded_objects (git_rawobj * raw , const git_oid * id )
864
- {
865
- if (!git_oid_cmp (id , & empty_blob )) {
866
- raw -> type = GIT_OBJ_BLOB ;
867
- raw -> len = 0 ;
868
- raw -> data = git__calloc (1 , sizeof (uint8_t ));
869
- return 0 ;
870
- } else if (!git_oid_cmp (id , & empty_tree )) {
871
- raw -> type = GIT_OBJ_TREE ;
872
- raw -> len = 0 ;
873
- raw -> data = git__calloc (1 , sizeof (uint8_t ));
874
- return 0 ;
875
- } else {
876
- return GIT_ENOTFOUND ;
925
+ if (error == GIT_PASSTHROUGH ) {
926
+ /*
927
+ * no backend has header-reading functionality
928
+ * so try using `git_odb_read` instead
929
+ */
930
+ error = git_odb_read (& object , db , id );
931
+ if (!error ) {
932
+ * len_p = object -> cached .size ;
933
+ * type_p = object -> cached .type ;
934
+ * out = object ;
935
+ }
877
936
}
937
+
938
+ return error ;
878
939
}
879
940
880
941
static int odb_read_1 (git_odb_object * * out , git_odb * db , const git_oid * id ,
@@ -885,7 +946,7 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
885
946
git_odb_object * object ;
886
947
bool found = false;
887
948
888
- if (!hardcoded_objects (& raw , id ))
949
+ if (!only_refreshed && odb_read_hardcoded (& raw , id ) == 0 )
889
950
found = true;
890
951
891
952
for (i = 0 ; i < db -> backends .length && !found ; ++ i ) {
@@ -939,6 +1000,29 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
939
1000
return error ;
940
1001
}
941
1002
1003
+ static int odb_otype_fast (git_otype * type_p , git_odb * db , const git_oid * id )
1004
+ {
1005
+ git_odb_object * object ;
1006
+ size_t _unused ;
1007
+ int error ;
1008
+
1009
+ if ((object = git_cache_get_raw (odb_cache (db ), id )) != NULL ) {
1010
+ * type_p = object -> cached .type ;
1011
+ return 0 ;
1012
+ }
1013
+
1014
+ error = odb_read_header_1 (& _unused , type_p , db , id , false);
1015
+
1016
+ if (error == GIT_PASSTHROUGH ) {
1017
+ error = odb_read_1 (& object , db , id , false);
1018
+ if (!error )
1019
+ * type_p = object -> cached .type ;
1020
+ git_odb_object_free (object );
1021
+ }
1022
+
1023
+ return error ;
1024
+ }
1025
+
942
1026
static int read_prefix_1 (git_odb_object * * out , git_odb * db ,
943
1027
const git_oid * key , size_t len , bool only_refreshed )
944
1028
{
0 commit comments