@@ -37,10 +37,32 @@ import (
3737// UnsupportedVersionString just holds an error message
3838const UnsupportedVersionString = "<unsupported cid version>"
3939
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 , * ErrInvalidCid :
56+ return true
57+ default :
58+ return false
59+ }
60+ }
61+
4062var (
4163 // ErrCidTooShort means that the cid passed to decode was not long
4264 // enough to be a valid Cid
43- ErrCidTooShort = errors .New ("cid too short" )
65+ ErrCidTooShort = ErrInvalidCid { errors .New ("cid too short" )}
4466
4567 // ErrInvalidEncoding means that selected encoding is not supported
4668 // by this Cid version
@@ -90,10 +112,10 @@ func tryNewCidV0(mhash mh.Multihash) (Cid, error) {
90112 // incorrectly detect it as CidV1 in the Version() method
91113 dec , err := mh .Decode (mhash )
92114 if err != nil {
93- return Undef , err
115+ return Undef , ErrInvalidCid { err }
94116 }
95117 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 )}
97119 }
98120 return Cid {string (mhash )}, nil
99121}
@@ -177,7 +199,7 @@ func Parse(v interface{}) (Cid, error) {
177199 case Cid :
178200 return v2 , nil
179201 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 )}
181203 }
182204}
183205
@@ -210,15 +232,15 @@ func Decode(v string) (Cid, error) {
210232 if len (v ) == 46 && v [:2 ] == "Qm" {
211233 hash , err := mh .FromB58String (v )
212234 if err != nil {
213- return Undef , err
235+ return Undef , ErrInvalidCid { err }
214236 }
215237
216238 return tryNewCidV0 (hash )
217239 }
218240
219241 _ , data , err := mbase .Decode (v )
220242 if err != nil {
221- return Undef , err
243+ return Undef , ErrInvalidCid { err }
222244 }
223245
224246 return Cast (data )
@@ -240,7 +262,7 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
240262 // check encoding is valid
241263 _ , err := mbase .NewEncoder (encoding )
242264 if err != nil {
243- return - 1 , err
265+ return - 1 , ErrInvalidCid { err }
244266 }
245267
246268 return encoding , nil
@@ -260,11 +282,11 @@ func ExtractEncoding(v string) (mbase.Encoding, error) {
260282func Cast (data []byte ) (Cid , error ) {
261283 nr , c , err := CidFromBytes (data )
262284 if err != nil {
263- return Undef , err
285+ return Undef , ErrInvalidCid { err }
264286 }
265287
266288 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" )}
268290 }
269291
270292 return c , nil
@@ -434,28 +456,28 @@ func (c Cid) Equals(o Cid) bool {
434456// UnmarshalJSON parses the JSON representation of a Cid.
435457func (c * Cid ) UnmarshalJSON (b []byte ) error {
436458 if len (b ) < 2 {
437- return fmt .Errorf ("invalid cid json blob" )
459+ return ErrInvalidCid { fmt .Errorf ("invalid cid json blob" )}
438460 }
439461 obj := struct {
440462 CidTarget string `json:"/"`
441463 }{}
442464 objptr := & obj
443465 err := json .Unmarshal (b , & objptr )
444466 if err != nil {
445- return err
467+ return ErrInvalidCid { err }
446468 }
447469 if objptr == nil {
448470 * c = Cid {}
449471 return nil
450472 }
451473
452474 if obj .CidTarget == "" {
453- return fmt .Errorf ("cid was incorrectly formatted" )
475+ return ErrInvalidCid { fmt .Errorf ("cid was incorrectly formatted" )}
454476 }
455477
456478 out , err := Decode (obj .CidTarget )
457479 if err != nil {
458- return err
480+ return ErrInvalidCid { err }
459481 }
460482
461483 * c = out
@@ -542,12 +564,12 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
542564 if p .Version == 0 && (p .MhType != mh .SHA2_256 ||
543565 (p .MhLength != 32 && p .MhLength != - 1 )) {
544566
545- return Undef , fmt .Errorf ("invalid v0 prefix" )
567+ return Undef , ErrInvalidCid { fmt .Errorf ("invalid v0 prefix" )}
546568 }
547569
548570 hash , err := mh .Sum (data , p .MhType , length )
549571 if err != nil {
550- return Undef , err
572+ return Undef , ErrInvalidCid { err }
551573 }
552574
553575 switch p .Version {
@@ -556,7 +578,7 @@ func (p Prefix) Sum(data []byte) (Cid, error) {
556578 case 1 :
557579 return NewCidV1 (p .Codec , hash ), nil
558580 default :
559- return Undef , fmt .Errorf ("invalid cid version" )
581+ return Undef , ErrInvalidCid { fmt .Errorf ("invalid cid version" )}
560582 }
561583}
562584
@@ -586,22 +608,22 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
586608 r := bytes .NewReader (buf )
587609 vers , err := varint .ReadUvarint (r )
588610 if err != nil {
589- return Prefix {}, err
611+ return Prefix {}, ErrInvalidCid { err }
590612 }
591613
592614 codec , err := varint .ReadUvarint (r )
593615 if err != nil {
594- return Prefix {}, err
616+ return Prefix {}, ErrInvalidCid { err }
595617 }
596618
597619 mhtype , err := varint .ReadUvarint (r )
598620 if err != nil {
599- return Prefix {}, err
621+ return Prefix {}, ErrInvalidCid { err }
600622 }
601623
602624 mhlen , err := varint .ReadUvarint (r )
603625 if err != nil {
604- return Prefix {}, err
626+ return Prefix {}, ErrInvalidCid { err }
605627 }
606628
607629 return Prefix {
@@ -615,34 +637,34 @@ func PrefixFromBytes(buf []byte) (Prefix, error) {
615637func CidFromBytes (data []byte ) (int , Cid , error ) {
616638 if len (data ) > 2 && data [0 ] == mh .SHA2_256 && data [1 ] == 32 {
617639 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" )}
619641 }
620642
621643 h , err := mh .Cast (data [:34 ])
622644 if err != nil {
623- return 0 , Undef , err
645+ return 0 , Undef , ErrInvalidCid { err }
624646 }
625647
626648 return 34 , Cid {string (h )}, nil
627649 }
628650
629651 vers , n , err := varint .FromUvarint (data )
630652 if err != nil {
631- return 0 , Undef , err
653+ return 0 , Undef , ErrInvalidCid { err }
632654 }
633655
634656 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 )}
636658 }
637659
638660 _ , cn , err := varint .FromUvarint (data [n :])
639661 if err != nil {
640- return 0 , Undef , err
662+ return 0 , Undef , ErrInvalidCid { err }
641663 }
642664
643665 mhnr , _ , err := mh .MHFromBytes (data [n + cn :])
644666 if err != nil {
645- return 0 , Undef , err
667+ return 0 , Undef , ErrInvalidCid { err }
646668 }
647669
648670 l := n + cn + mhnr
@@ -705,32 +727,32 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
705727 // The varint package wants a io.ByteReader, so we must wrap our io.Reader.
706728 vers , err := varint .ReadUvarint (br )
707729 if err != nil {
708- return len (br .dst ), Undef , err
730+ return len (br .dst ), Undef , ErrInvalidCid { err }
709731 }
710732
711733 // If we have a CIDv0, read the rest of the bytes and cast the buffer.
712734 if vers == mh .SHA2_256 {
713735 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 }
715737 }
716738
717739 br .dst = br .dst [:34 ]
718740 h , err := mh .Cast (br .dst )
719741 if err != nil {
720- return len (br .dst ), Undef , err
742+ return len (br .dst ), Undef , ErrInvalidCid { err }
721743 }
722744
723745 return len (br .dst ), Cid {string (h )}, nil
724746 }
725747
726748 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 )}
728750 }
729751
730752 // CID block encoding multicodec.
731753 _ , err = varint .ReadUvarint (br )
732754 if err != nil {
733- return len (br .dst ), Undef , err
755+ return len (br .dst ), Undef , ErrInvalidCid { err }
734756 }
735757
736758 // 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) {
741763 // Multihash hash function code.
742764 _ , err = varint .ReadUvarint (br )
743765 if err != nil {
744- return len (br .dst ), Undef , err
766+ return len (br .dst ), Undef , ErrInvalidCid { err }
745767 }
746768
747769 // Multihash digest length.
748770 mhl , err := varint .ReadUvarint (br )
749771 if err != nil {
750- return len (br .dst ), Undef , err
772+ return len (br .dst ), Undef , ErrInvalidCid { err }
751773 }
752774
753775 // Refuse to make large allocations to prevent OOMs due to bugs.
754776 const maxDigestAlloc = 32 << 20 // 32MiB
755777 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 )}
757779 }
758780
759781 // Fine to convert mhl to int, given maxDigestAlloc.
@@ -772,15 +794,15 @@ func CidFromReader(r io.Reader) (int, Cid, error) {
772794 if n , err := io .ReadFull (r , br .dst [prefixLength :cidLength ]); err != nil {
773795 // We can't use len(br.dst) here,
774796 // as we've only read n bytes past prefixLength.
775- return prefixLength + n , Undef , err
797+ return prefixLength + n , Undef , ErrInvalidCid { err }
776798 }
777799
778800 // This simply ensures the multihash is valid.
779801 // TODO: consider removing this bit, as it's probably redundant;
780802 // for now, it helps ensure consistency with CidFromBytes.
781803 _ , _ , err = mh .MHFromBytes (br .dst [mhStart :])
782804 if err != nil {
783- return len (br .dst ), Undef , err
805+ return len (br .dst ), Undef , ErrInvalidCid { err }
784806 }
785807
786808 return len (br .dst ), Cid {string (br .dst )}, nil
0 commit comments