Commit f6390fed authored by Steven Allen's avatar Steven Allen

Make ScanForLinks non-recursive

This way, we can't blow out our stack.
parent cdf4113c
...@@ -17,67 +17,55 @@ const maxCidLength = 100 ...@@ -17,67 +17,55 @@ const maxCidLength = 100
const maxHeaderSize = 9 const maxHeaderSize = 9
func ScanForLinks(br io.Reader, cb func(cid.Cid)) error { func ScanForLinks(br io.Reader, cb func(cid.Cid)) error {
buf := make([]byte, maxCidLength) scratch := make([]byte, maxCidLength)
return scanForLinksRec(br, cb, buf) for remaining := uint64(1); remaining > 0; remaining-- {
} maj, extra, err := CborReadHeaderBuf(br, scratch)
func scanForLinksRec(br io.Reader, cb func(cid.Cid), scratch []byte) error {
maj, extra, err := CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
switch maj {
case MajUnsignedInt, MajNegativeInt, MajOther:
case MajByteString, MajTextString:
_, err := io.CopyN(ioutil.Discard, br, int64(extra))
if err != nil { if err != nil {
return err return err
} }
case MajTag:
if extra == 42 {
maj, extra, err = CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != MajByteString {
return fmt.Errorf("expected cbor type 'byte string' in input")
}
if extra > maxCidLength {
return fmt.Errorf("string in cbor input too long")
}
if _, err := io.ReadAtLeast(br, scratch[:extra], int(extra)); err != nil {
return err
}
c, err := cid.Cast(scratch[1:extra]) switch maj {
case MajUnsignedInt, MajNegativeInt, MajOther:
case MajByteString, MajTextString:
_, err := io.CopyN(ioutil.Discard, br, int64(extra))
if err != nil { if err != nil {
return err return err
} }
cb(c) case MajTag:
if extra == 42 {
} else { maj, extra, err = CborReadHeaderBuf(br, scratch)
if err := scanForLinksRec(br, cb, scratch); err != nil { if err != nil {
return err return err
} }
}
case MajArray: if maj != MajByteString {
for i := 0; i < int(extra); i++ { return fmt.Errorf("expected cbor type 'byte string' in input")
if err := scanForLinksRec(br, cb, scratch); err != nil { }
return err
} if extra > maxCidLength {
} return fmt.Errorf("string in cbor input too long")
case MajMap: }
for i := 0; i < int(extra*2); i++ {
if err := scanForLinksRec(br, cb, scratch); err != nil { if _, err := io.ReadAtLeast(br, scratch[:extra], int(extra)); err != nil {
return err return err
}
c, err := cid.Cast(scratch[1:extra])
if err != nil {
return err
}
cb(c)
} else {
remaining++
} }
case MajArray:
remaining += extra
case MajMap:
remaining += (extra * 2)
default:
return fmt.Errorf("unhandled cbor type: %d", maj)
} }
default:
return fmt.Errorf("unhandled cbor type: %d", maj)
} }
return nil return nil
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment