@@ -37,10 +37,32 @@ import (
37
37
// UnsupportedVersionString just holds an error message
38
38
const UnsupportedVersionString = "<unsupported cid version>"
39
39
40
+ // ErrInvalidCid is an error that indicates that a CID is invalid.
41
+ type ErrInvalidCid struct {
42
+ Err error
43
+ }
44
+
45
+ func (e * ErrInvalidCid ) Error () string {
46
+ return fmt .Sprintf ("invalid cid: %s" , e .Err )
47
+ }
48
+
49
+ func (e * ErrInvalidCid ) Unwrap () error {
50
+ return e .Err
51
+ }
52
+
53
+ func (e * ErrInvalidCid ) Is (err error ) bool {
54
+ switch err .(type ) {
55
+ case * ErrInvalidCid :
56
+ return true
57
+ default :
58
+ return false
59
+ }
60
+ }
61
+
40
62
var (
41
63
// ErrCidTooShort means that the cid passed to decode was not long
42
64
// enough to be a valid Cid
43
- ErrCidTooShort = errors .New ("cid too short" )
65
+ ErrCidTooShort = & ErrInvalidCid { errors .New ("cid too short" )}
44
66
45
67
// ErrInvalidEncoding means that selected encoding is not supported
46
68
// by this Cid version
@@ -90,10 +112,10 @@ func tryNewCidV0(mhash mh.Multihash) (Cid, error) {
90
112
// incorrectly detect it as CidV1 in the Version() method
91
113
dec , err := mh .Decode (mhash )
92
114
if err != nil {
93
- return Undef , err
115
+ return Undef , & ErrInvalidCid { err }
94
116
}
95
117
if dec .Code != mh .SHA2_256 || dec .Length != 32 {
96
- return Undef , fmt .Errorf ("invalid hash for cidv0 %d-%d" , dec .Code , dec .Length )
118
+ return Undef , & ErrInvalidCid { fmt .Errorf ("invalid hash for cidv0 %d-%d" , dec .Code , dec .Length )}
97
119
}
98
120
return Cid {string (mhash )}, nil
99
121
}
@@ -177,7 +199,7 @@ func Parse(v interface{}) (Cid, error) {
177
199
case Cid :
178
200
return v2 , nil
179
201
default :
180
- return Undef , fmt .Errorf ("can't parse %+v as Cid" , v2 )
202
+ return Undef , & ErrInvalidCid { fmt .Errorf ("can't parse %+v as Cid" , v2 )}
181
203
}
182
204
}
183
205
@@ -210,15 +232,15 @@ func Decode(v string) (Cid, error) {
210
232
if len (v ) == 46 && v [:2 ] == "Qm" {
211
233
hash , err := mh .FromB58String (v )
212
234
if err != nil {
213
- return Undef , err
235
+ return Undef , & ErrInvalidCid { err }
214
236
}
215
237
216
238
return tryNewCidV0 (hash )
217
239
}
218
240
219
241
_ , data , err := mbase .Decode (v )
220
242
if err != nil {
221
- return Undef , err
243
+ return Undef , & ErrInvalidCid { err }
222
244
}
223
245
224
246
return Cast (data )
@@ -240,7 +262,7 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
240
262
// check encoding is valid
241
263
_ , err := mbase .NewEncoder (encoding )
242
264
if err != nil {
243
- return - 1 , err
265
+ return - 1 , & ErrInvalidCid { err }
244
266
}
245
267
246
268
return encoding , nil
@@ -260,11 +282,11 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
260
282
func Cast (data []byte ) (Cid , error ) {
261
283
nr , c , err := CidFromBytes (data )
262
284
if err != nil {
263
- return Undef , err
285
+ return Undef , & ErrInvalidCid { err }
264
286
}
265
287
266
288
if nr != len (data ) {
267
- return Undef , fmt .Errorf ("trailing bytes in data buffer passed to cid Cast" )
289
+ return Undef , & ErrInvalidCid { fmt .Errorf ("trailing bytes in data buffer passed to cid Cast" )}
268
290
}
269
291
270
292
return c , nil
@@ -615,34 +637,34 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
615
637
func CidFromBytes (data []byte ) (int , Cid , error ) {
616
638
if len (data ) > 2 && data [0 ] == mh .SHA2_256 && data [1 ] == 32 {
617
639
if len (data ) < 34 {
618
- return 0 , Undef , fmt .Errorf ("not enough bytes for cid v0" )
640
+ return 0 , Undef , & ErrInvalidCid { fmt .Errorf ("not enough bytes for cid v0" )}
619
641
}
620
642
621
643
h , err := mh .Cast (data [:34 ])
622
644
if err != nil {
623
- return 0 , Undef , err
645
+ return 0 , Undef , & ErrInvalidCid { err }
624
646
}
625
647
626
648
return 34 , Cid {string (h )}, nil
627
649
}
628
650
629
651
vers , n , err := varint .FromUvarint (data )
630
652
if err != nil {
631
- return 0 , Undef , err
653
+ return 0 , Undef , & ErrInvalidCid { err }
632
654
}
633
655
634
656
if vers != 1 {
635
- return 0 , Undef , fmt .Errorf ("expected 1 as the cid version number, got: %d" , vers )
657
+ return 0 , Undef , & ErrInvalidCid { fmt .Errorf ("expected 1 as the cid version number, got: %d" , vers )}
636
658
}
637
659
638
660
_ , cn , err := varint .FromUvarint (data [n :])
639
661
if err != nil {
640
- return 0 , Undef , err
662
+ return 0 , Undef , & ErrInvalidCid { err }
641
663
}
642
664
643
665
mhnr , _ , err := mh .MHFromBytes (data [n + cn :])
644
666
if err != nil {
645
- return 0 , Undef , err
667
+ return 0 , Undef , & ErrInvalidCid { err }
646
668
}
647
669
648
670
l := n + cn + mhnr
@@ -705,32 +727,32 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
705
727
// The varint package wants a io.ByteReader, so we must wrap our io.Reader.
706
728
vers , err := varint .ReadUvarint (br )
707
729
if err != nil {
708
- return len (br .dst ), Undef , err
730
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
709
731
}
710
732
711
733
// If we have a CIDv0, read the rest of the bytes and cast the buffer.
712
734
if vers == mh .SHA2_256 {
713
735
if n , err := io .ReadFull (r , br .dst [1 :34 ]); err != nil {
714
- return len (br .dst ) + n , Undef , err
736
+ return len (br .dst ) + n , Undef , & ErrInvalidCid { err }
715
737
}
716
738
717
739
br .dst = br .dst [:34 ]
718
740
h , err := mh .Cast (br .dst )
719
741
if err != nil {
720
- return len (br .dst ), Undef , err
742
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
721
743
}
722
744
723
745
return len (br .dst ), Cid {string (h )}, nil
724
746
}
725
747
726
748
if vers != 1 {
727
- return len (br .dst ), Undef , fmt .Errorf ("expected 1 as the cid version number, got: %d" , vers )
749
+ return len (br .dst ), Undef , & ErrInvalidCid { fmt .Errorf ("expected 1 as the cid version number, got: %d" , vers )}
728
750
}
729
751
730
752
// CID block encoding multicodec.
731
753
_ , err = varint .ReadUvarint (br )
732
754
if err != nil {
733
- return len (br .dst ), Undef , err
755
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
734
756
}
735
757
736
758
// We could replace most of the code below with go-multihash's ReadMultihash.
@@ -741,19 +763,19 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
741
763
// Multihash hash function code.
742
764
_ , err = varint .ReadUvarint (br )
743
765
if err != nil {
744
- return len (br .dst ), Undef , err
766
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
745
767
}
746
768
747
769
// Multihash digest length.
748
770
mhl , err := varint .ReadUvarint (br )
749
771
if err != nil {
750
- return len (br .dst ), Undef , err
772
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
751
773
}
752
774
753
775
// Refuse to make large allocations to prevent OOMs due to bugs.
754
776
const maxDigestAlloc = 32 << 20 // 32MiB
755
777
if mhl > maxDigestAlloc {
756
- return len (br .dst ), Undef , fmt .Errorf ("refusing to allocate %d bytes for a digest" , mhl )
778
+ return len (br .dst ), Undef , & ErrInvalidCid { fmt .Errorf ("refusing to allocate %d bytes for a digest" , mhl )}
757
779
}
758
780
759
781
// Fine to convert mhl to int, given maxDigestAlloc.
@@ -772,15 +794,15 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
772
794
if n , err := io .ReadFull (r , br .dst [prefixLength :cidLength ]); err != nil {
773
795
// We can't use len(br.dst) here,
774
796
// as we've only read n bytes past prefixLength.
775
- return prefixLength + n , Undef , err
797
+ return prefixLength + n , Undef , & ErrInvalidCid { err }
776
798
}
777
799
778
800
// This simply ensures the multihash is valid.
779
801
// TODO: consider removing this bit, as it's probably redundant;
780
802
// for now, it helps ensure consistency with CidFromBytes.
781
803
_ , _ , err = mh .MHFromBytes (br .dst [mhStart :])
782
804
if err != nil {
783
- return len (br .dst ), Undef , err
805
+ return len (br .dst ), Undef , & ErrInvalidCid { err }
784
806
}
785
807
786
808
return len (br .dst ), Cid {string (br .dst )}, nil
0 commit comments