1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17
18 package blob
19
20 import (
21 "bytes"
22 "crypto/sha1"
23 "crypto/sha256"
24 "errors"
25 "fmt"
26 "hash"
27 "io"
28 "reflect"
29 "strings"
30 )
31
32
33
34 const Pattern = `\b([a-z][a-z0-9]*)-([a-f0-9]+)\b`
35
36
37
38
39 type Ref struct {
40 digest digestType
41 }
42
43
44
45 type SizedRef struct {
46 Ref Ref `json:"blobRef"`
47 Size uint32 `json:"size"`
48 }
49
50
51 func (sr SizedRef) Less(o SizedRef) bool {
52 return sr.Ref.Less(o.Ref)
53 }
54
55 func (sr SizedRef) Valid() bool { return sr.Ref.Valid() }
56
57 func (sr SizedRef) HashMatches(h hash.Hash) bool { return sr.Ref.HashMatches(h) }
58
59 func (sr SizedRef) String() string {
60 return fmt.Sprintf("[%s; %d bytes]", sr.Ref.String(), sr.Size)
61 }
62
63
64
65
66 type digestType interface {
67 bytes() []byte
68 digestName() string
69 newHash() hash.Hash
70 equalString(string) bool
71 hasPrefix(string) bool
72 }
73
74 func (r Ref) String() string {
75 if r.digest == nil {
76 return "<invalid-blob.Ref>"
77 }
78 dname := r.digest.digestName()
79 bs := r.digest.bytes()
80 buf := getBuf(len(dname) + 1 + len(bs)*2)[:0]
81 defer putBuf(buf)
82 return string(r.appendString(buf))
83 }
84
85
86 func (r Ref) StringMinusOne() string {
87 if r.digest == nil {
88 return "<invalid-blob.Ref>"
89 }
90 dname := r.digest.digestName()
91 bs := r.digest.bytes()
92 buf := getBuf(len(dname) + 1 + len(bs)*2)[:0]
93 defer putBuf(buf)
94 buf = r.appendString(buf)
95 buf[len(buf)-1]--
96 return string(buf)
97 }
98
99
100
101 func (r Ref) EqualString(s string) bool { return r.digest.equalString(s) }
102
103
104
105
106
107 func (r Ref) HasPrefix(s string) bool { return r.digest.hasPrefix(s) }
108
109 func (r Ref) appendString(buf []byte) []byte {
110 dname := r.digest.digestName()
111 bs := r.digest.bytes()
112 buf = append(buf, dname...)
113 buf = append(buf, '-')
114 for _, b := range bs {
115 buf = append(buf, hexDigit[b>>4], hexDigit[b&0xf])
116 }
117 if o, ok := r.digest.(otherDigest); ok && o.odd {
118 buf = buf[:len(buf)-1]
119 }
120 return buf
121 }
122
123
124
125 func (r Ref) HashName() string {
126 if r.digest == nil {
127 panic("HashName called on invalid Ref")
128 }
129 return r.digest.digestName()
130 }
131
132
133
134 func (r Ref) Digest() string {
135 if r.digest == nil {
136 panic("Digest called on invalid Ref")
137 }
138 bs := r.digest.bytes()
139 buf := getBuf(len(bs) * 2)[:0]
140 defer putBuf(buf)
141 for _, b := range bs {
142 buf = append(buf, hexDigit[b>>4], hexDigit[b&0xf])
143 }
144 if o, ok := r.digest.(otherDigest); ok && o.odd {
145 buf = buf[:len(buf)-1]
146 }
147 return string(buf)
148 }
149
150 func (r Ref) DigestPrefix(digits int) string {
151 v := r.Digest()
152 if len(v) < digits {
153 return v
154 }
155 return v[:digits]
156 }
157
158 func (r Ref) DomID() string {
159 if !r.Valid() {
160 return ""
161 }
162 return "camli-" + r.String()
163 }
164
165 func (r Ref) Sum32() uint32 {
166 var v uint32
167 for _, b := range r.digest.bytes()[:4] {
168 v = v<<8 | uint32(b)
169 }
170 return v
171 }
172
173 func (r Ref) Sum64() uint64 {
174 var v uint64
175 for _, b := range r.digest.bytes()[:8] {
176 v = v<<8 | uint64(b)
177 }
178 return v
179 }
180
181
182
183 func (r Ref) Hash() hash.Hash {
184 return r.digest.newHash()
185 }
186
187 func (r Ref) HashMatches(h hash.Hash) bool {
188 if r.digest == nil {
189 return false
190 }
191 return bytes.Equal(h.Sum(nil), r.digest.bytes())
192 }
193
194 const hexDigit = "0123456789abcdef"
195
196 func (r Ref) Valid() bool { return r.digest != nil }
197
198 func (r Ref) IsSupported() bool {
199 if !r.Valid() {
200 return false
201 }
202 _, ok := metaFromString[r.digest.digestName()]
203 return ok
204 }
205
206
207
208
209 func ParseKnown(s string) (ref Ref, ok bool) {
210 return parse(s, false)
211 }
212
213
214
215 func Parse(s string) (ref Ref, ok bool) {
216 return parse(s, true)
217 }
218
219 func parse(s string, allowAll bool) (ref Ref, ok bool) {
220 i := strings.Index(s, "-")
221 if i < 0 {
222 return
223 }
224 name := s[:i]
225 hex := s[i+1:]
226 meta, ok := metaFromString[name]
227 if !ok {
228 if allowAll || testRefType[name] {
229 return parseUnknown(name, hex)
230 }
231 return
232 }
233 if len(hex) != meta.size*2 {
234 ok = false
235 return
236 }
237 dt, ok := meta.ctors(hex)
238 if !ok {
239 return
240 }
241 return Ref{dt}, true
242 }
243
244 var testRefType = map[string]bool{
245 "fakeref": true,
246 "testref": true,
247 "perma": true,
248 }
249
250
251 func ParseBytes(s []byte) (ref Ref, ok bool) {
252 i := bytes.IndexByte(s, '-')
253 if i < 0 {
254 return
255 }
256 name := s[:i]
257 hex := s[i+1:]
258 meta, ok := metaFromBytes(name)
259 if !ok {
260 return parseUnknown(string(name), string(hex))
261 }
262 if len(hex) != meta.size*2 {
263 ok = false
264 return
265 }
266 dt, ok := meta.ctorb(hex)
267 if !ok {
268 return
269 }
270 return Ref{dt}, true
271 }
272
273
274
275 func ParseOrZero(s string) Ref {
276 ref, ok := Parse(s)
277 if !ok {
278 return Ref{}
279 }
280 return ref
281 }
282
283
284 func MustParse(s string) Ref {
285 ref, ok := Parse(s)
286 if !ok {
287 panic("Invalid blobref " + s)
288 }
289 return ref
290 }
291
292
293 func hexVal(b byte, bad *bool) byte {
294 if '0' <= b && b <= '9' {
295 return b - '0'
296 }
297 if 'a' <= b && b <= 'f' {
298 return b - 'a' + 10
299 }
300 *bad = true
301 return 0
302 }
303
304 func validDigestName(name string) bool {
305 if name == "" {
306 return false
307 }
308 for _, r := range name {
309 if 'a' <= r && r <= 'z' {
310 continue
311 }
312 if '0' <= r && r <= '9' {
313 continue
314 }
315 return false
316 }
317 return true
318 }
319
320
321
322 func parseUnknown(digest, hex string) (ref Ref, ok bool) {
323 if !validDigestName(digest) {
324 return
325 }
326
327
328 odd := false
329 if len(hex)%2 != 0 {
330 hex += "0"
331 odd = true
332 }
333
334 if len(hex) < 2 || len(hex)%2 != 0 || len(hex) > maxOtherDigestLen*2 {
335 return
336 }
337 o := otherDigest{
338 name: digest,
339 sumLen: len(hex) / 2,
340 odd: odd,
341 }
342 bad := false
343 for i := 0; i < len(hex); i += 2 {
344 o.sum[i/2] = hexVal(hex[i], &bad)<<4 | hexVal(hex[i+1], &bad)
345 }
346 if bad {
347 return
348 }
349 return Ref{o}, true
350 }
351
352 func sha1FromBinary(b []byte) digestType {
353 var d sha1Digest
354 if len(d) != len(b) {
355 panic("bogus sha-1 length")
356 }
357 copy(d[:], b)
358 return d
359 }
360
361 func sha1FromHexString(hex string) (digestType, bool) {
362 var d sha1Digest
363 var bad bool
364 for i := 0; i < len(hex); i += 2 {
365 d[i/2] = hexVal(hex[i], &bad)<<4 | hexVal(hex[i+1], &bad)
366 }
367 if bad {
368 return nil, false
369 }
370 return d, true
371 }
372
373
374 func sha1FromHexBytes(hex []byte) (digestType, bool) {
375 var d sha1Digest
376 var bad bool
377 for i := 0; i < len(hex); i += 2 {
378 d[i/2] = hexVal(hex[i], &bad)<<4 | hexVal(hex[i+1], &bad)
379 }
380 if bad {
381 return nil, false
382 }
383 return d, true
384 }
385
386 func sha224FromBinary(b []byte) digestType {
387 var d sha224Digest
388 if len(d) != len(b) {
389 panic("bogus sha-224 length")
390 }
391 copy(d[:], b)
392 return d
393 }
394
395 func sha224FromHexString(hex string) (digestType, bool) {
396 var d sha224Digest
397 var bad bool
398 for i := 0; i < len(hex); i += 2 {
399 d[i/2] = hexVal(hex[i], &bad)<<4 | hexVal(hex[i+1], &bad)
400 }
401 if bad {
402 return nil, false
403 }
404 return d, true
405 }
406
407
408 func sha224FromHexBytes(hex []byte) (digestType, bool) {
409 var d sha224Digest
410 var bad bool
411 for i := 0; i < len(hex); i += 2 {
412 d[i/2] = hexVal(hex[i], &bad)<<4 | hexVal(hex[i+1], &bad)
413 }
414 if bad {
415 return nil, false
416 }
417 return d, true
418 }
419
420
421
422 func RefFromHash(h hash.Hash) Ref {
423 meta, ok := metaFromType[hashSig{reflect.TypeOf(h), h.Size()}]
424 if !ok {
425 panic(fmt.Sprintf("Currently-unsupported hash type %T", h))
426 }
427 return Ref{meta.ctor(h.Sum(nil))}
428 }
429
430
431
432 func RefFromString(s string) Ref {
433 h := NewHash()
434 io.WriteString(h, s)
435 return RefFromHash(h)
436 }
437
438
439
440 func RefFromBytes(b []byte) Ref {
441 h := NewHash()
442 h.Write(b)
443 return RefFromHash(h)
444 }
445
446 type sha1Digest [20]byte
447
448 func (d sha1Digest) digestName() string { return "sha1" }
449 func (d sha1Digest) bytes() []byte { return d[:] }
450 func (d sha1Digest) newHash() hash.Hash { return sha1.New() }
451 func (d sha1Digest) equalString(s string) bool {
452 if len(s) != 45 {
453 return false
454 }
455 if !strings.HasPrefix(s, "sha1-") {
456 return false
457 }
458 s = s[len("sha1-"):]
459 for i, b := range d[:] {
460 if s[i*2] != hexDigit[b>>4] || s[i*2+1] != hexDigit[b&0xf] {
461 return false
462 }
463 }
464 return true
465 }
466
467 func (d sha1Digest) hasPrefix(s string) bool {
468 if len(s) > 45 {
469 return false
470 }
471 if len(s) == 45 {
472 return d.equalString(s)
473 }
474 if !strings.HasPrefix(s, "sha1-") {
475 return false
476 }
477 s = s[len("sha1-"):]
478 if len(s) == 0 {
479
480 return false
481 }
482 for i, b := range d[:] {
483 even := i * 2
484 if even == len(s) {
485 break
486 }
487 if s[even] != hexDigit[b>>4] {
488 return false
489 }
490 odd := i*2 + 1
491 if odd == len(s) {
492 break
493 }
494 if s[odd] != hexDigit[b&0xf] {
495 return false
496 }
497 }
498 return true
499 }
500
501 type sha224Digest [28]byte
502
503 const sha224StrLen = 63
504
505 func (d sha224Digest) digestName() string { return "sha224" }
506 func (d sha224Digest) bytes() []byte { return d[:] }
507 func (d sha224Digest) newHash() hash.Hash { return sha256.New224() }
508 func (d sha224Digest) equalString(s string) bool {
509 if len(s) != sha224StrLen {
510 return false
511 }
512 if !strings.HasPrefix(s, "sha224-") {
513 return false
514 }
515 s = s[len("sha224-"):]
516 for i, b := range d[:] {
517 if s[i*2] != hexDigit[b>>4] || s[i*2+1] != hexDigit[b&0xf] {
518 return false
519 }
520 }
521 return true
522 }
523
524 func (d sha224Digest) hasPrefix(s string) bool {
525 if len(s) > sha224StrLen {
526 return false
527 }
528 if len(s) == sha224StrLen {
529 return d.equalString(s)
530 }
531 if !strings.HasPrefix(s, "sha224-") {
532 return false
533 }
534 s = s[len("sha224-"):]
535 if len(s) == 0 {
536
537 return false
538 }
539 for i, b := range d[:] {
540 even := i * 2
541 if even == len(s) {
542 break
543 }
544 if s[even] != hexDigit[b>>4] {
545 return false
546 }
547 odd := i*2 + 1
548 if odd == len(s) {
549 break
550 }
551 if s[odd] != hexDigit[b&0xf] {
552 return false
553 }
554 }
555 return true
556 }
557
558 const maxOtherDigestLen = 128
559
560 type otherDigest struct {
561 name string
562 sum [maxOtherDigestLen]byte
563 sumLen int
564 odd bool
565 }
566
567 func (d otherDigest) digestName() string { return d.name }
568 func (d otherDigest) bytes() []byte { return d.sum[:d.sumLen] }
569 func (d otherDigest) newHash() hash.Hash { return nil }
570 func (d otherDigest) equalString(s string) bool {
571 wantLen := len(d.name) + len("-") + 2*d.sumLen
572 if d.odd {
573 wantLen--
574 }
575 if len(s) != wantLen || !strings.HasPrefix(s, d.name) || s[len(d.name)] != '-' {
576 return false
577 }
578 s = s[len(d.name)+1:]
579 for i, b := range d.sum[:d.sumLen] {
580 if s[i*2] != hexDigit[b>>4] {
581 return false
582 }
583 if i == d.sumLen-1 && d.odd {
584 break
585 }
586 if s[i*2+1] != hexDigit[b&0xf] {
587 return false
588 }
589 }
590 return true
591 }
592
593 func (d otherDigest) hasPrefix(s string) bool {
594 maxLen := len(d.name) + len("-") + 2*d.sumLen
595 if d.odd {
596 maxLen--
597 }
598 if len(s) > maxLen || !strings.HasPrefix(s, d.name) || s[len(d.name)] != '-' {
599 return false
600 }
601 if len(s) == maxLen {
602 return d.equalString(s)
603 }
604 s = s[len(d.name)+1:]
605 if len(s) == 0 {
606
607 return false
608 }
609 for i, b := range d.sum[:d.sumLen] {
610 even := i * 2
611 if even == len(s) {
612 break
613 }
614 if s[even] != hexDigit[b>>4] {
615 return false
616 }
617 odd := i*2 + 1
618 if odd == len(s) {
619 break
620 }
621 if i == d.sumLen-1 && d.odd {
622 break
623 }
624 if s[odd] != hexDigit[b&0xf] {
625 return false
626 }
627 }
628 return true
629 }
630
631 var (
632 sha1Meta = &digestMeta{
633 ctor: sha1FromBinary,
634 ctors: sha1FromHexString,
635 ctorb: sha1FromHexBytes,
636 size: sha1.Size,
637 }
638 sha224Meta = &digestMeta{
639 ctor: sha224FromBinary,
640 ctors: sha224FromHexString,
641 ctorb: sha224FromHexBytes,
642 size: sha256.Size224,
643 }
644 )
645
646 var metaFromString = map[string]*digestMeta{
647 "sha1": sha1Meta,
648 "sha224": sha224Meta,
649 }
650
651 type blobTypeAndMeta struct {
652 name []byte
653 meta *digestMeta
654 }
655
656 var metas []blobTypeAndMeta
657
658 func metaFromBytes(name []byte) (meta *digestMeta, ok bool) {
659 for _, bm := range metas {
660 if bytes.Equal(name, bm.name) {
661 return bm.meta, true
662 }
663 }
664 return
665 }
666
667 func init() {
668 for name, meta := range metaFromString {
669 metas = append(metas, blobTypeAndMeta{
670 name: []byte(name),
671 meta: meta,
672 })
673 }
674 }
675
676
677 func HashFuncs() []string {
678 hashes := make([]string, len(metas))
679 for i, m := range metas {
680 hashes[i] = string(m.name)
681 }
682 return hashes
683 }
684
685 var (
686 sha1Type = reflect.TypeOf(sha1.New())
687 sha224Type = reflect.TypeOf(sha256.New224())
688 )
689
690
691
692
693 type hashSig struct {
694 rt reflect.Type
695 size int
696 }
697
698 var metaFromType = map[hashSig]*digestMeta{
699 {sha1Type, sha1.Size}: sha1Meta,
700 {sha224Type, sha256.Size224}: sha224Meta,
701 }
702
703 type digestMeta struct {
704 ctor func(binary []byte) digestType
705 ctors func(hex string) (digestType, bool)
706 ctorb func(hex []byte) (digestType, bool)
707 size int
708 }
709
710 var bufPool = make(chan []byte, 20)
711
712 func getBuf(size int) []byte {
713 for {
714 select {
715 case b := <-bufPool:
716 if cap(b) >= size {
717 return b[:size]
718 }
719 default:
720 return make([]byte, size)
721 }
722 }
723 }
724
725 func putBuf(b []byte) {
726 select {
727 case bufPool <- b:
728 default:
729 }
730 }
731
732
733
734 func NewHash() hash.Hash {
735 return sha256.New224()
736 }
737
738 func ValidRefString(s string) bool {
739
740 return ParseOrZero(s).Valid()
741 }
742
743 var null = []byte(`null`)
744
745 func (r *Ref) UnmarshalJSON(d []byte) error {
746 if r.digest != nil {
747 return errors.New("Can't UnmarshalJSON into a non-zero Ref")
748 }
749 if len(d) == 0 || bytes.Equal(d, null) {
750 return nil
751 }
752 if len(d) < 2 || d[0] != '"' || d[len(d)-1] != '"' {
753 return fmt.Errorf("blob: expecting a JSON string to unmarshal, got %q", d)
754 }
755 d = d[1 : len(d)-1]
756 p, ok := ParseBytes(d)
757 if !ok {
758 return fmt.Errorf("blobref: invalid blobref %q (%d)", d, len(d))
759 }
760 *r = p
761 return nil
762 }
763
764 func (r Ref) MarshalJSON() ([]byte, error) {
765 if !r.Valid() {
766 return null, nil
767 }
768 dname := r.digest.digestName()
769 bs := r.digest.bytes()
770 buf := make([]byte, 0, 3+len(dname)+len(bs)*2)
771 buf = append(buf, '"')
772 buf = r.appendString(buf)
773 buf = append(buf, '"')
774 return buf, nil
775 }
776
777
778 func (r Ref) MarshalBinary() (data []byte, err error) {
779 dname := r.digest.digestName()
780 bs := r.digest.bytes()
781 data = make([]byte, 0, len(dname)+1+len(bs))
782 data = append(data, dname...)
783 data = append(data, '-')
784 data = append(data, bs...)
785 return
786 }
787
788
789 func (r *Ref) UnmarshalBinary(data []byte) error {
790 if r.digest != nil {
791 return errors.New("Can't UnmarshalBinary into a non-zero Ref")
792 }
793 i := bytes.IndexByte(data, '-')
794 if i < 1 {
795 return errors.New("no digest name")
796 }
797
798 digName := string(data[:i])
799 buf := data[i+1:]
800
801 meta, ok := metaFromString[digName]
802 if !ok {
803 r2, ok := parseUnknown(digName, fmt.Sprintf("%x", buf))
804 if !ok {
805 return errors.New("invalid blobref binary data")
806 }
807 *r = r2
808 return nil
809 }
810 if len(buf) != meta.size {
811 return errors.New("wrong size of data for digest " + digName)
812 }
813 r.digest = meta.ctor(buf)
814 return nil
815 }
816
817
818 func (r Ref) Less(o Ref) bool {
819 if r.Valid() != o.Valid() {
820 return o.Valid()
821 }
822 if !r.Valid() {
823 return false
824 }
825 if n1, n2 := r.digest.digestName(), o.digest.digestName(); n1 != n2 {
826 return n1 < n2
827 }
828 return bytes.Compare(r.digest.bytes(), o.digest.bytes()) < 0
829 }
830
831
832 type ByRef []Ref
833
834 func (s ByRef) Len() int { return len(s) }
835 func (s ByRef) Less(i, j int) bool { return s[i].Less(s[j]) }
836 func (s ByRef) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
837
838
839 type SizedByRef []SizedRef
840
841 func (s SizedByRef) Len() int { return len(s) }
842 func (s SizedByRef) Less(i, j int) bool { return s[i].Less(s[j]) }
843 func (s SizedByRef) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
844
845
846
847 func TypeAlphabet(typ string) string {
848 switch typ {
849 case "sha1":
850 return hexDigit
851 case "sha224":
852 return hexDigit
853 }
854 return ""
855 }